Skip to content

Commit a26c1ff

Browse files
committed
docs(docs): address review of the site improvements
Fix what the review of #470 found in the new and merged pages: - Recipes need the HTTP endpoint, keep the form marker before the fix, fall back to the stack and scan-providers when an error has no owner, and describe verify-fix as the lighter check it is. - The NativeScript main.ts sample keeps runNativeScriptAngularApp(), and the demo runs the app in a second terminal. - Angular Native shows the URL polyfill install and import, and Vite installs h3 1 for the render tracing middleware. - Installation says the overlay is only needed for live data, and the features page no longer promises a screenshot for every tab. - Badges stay visible through a prerelease of their until version. - The llms.txt dev middleware passes errors to next(), and its tests run against a fixture site.
1 parent d3bfac8 commit a26c1ff

11 files changed

Lines changed: 166 additions & 45 deletions

File tree

‎apps/docs/llms-txt.plugin.spec.ts‎

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,84 @@
1-
import config from './src/ngmd.config.ts';
1+
import {mkdirSync, mkdtempSync, rmSync, writeFileSync} from 'node:fs';
2+
import {tmpdir} from 'node:os';
3+
import {join} from 'node:path';
4+
import type {NgmdConfig} from './src/ngmd.config.ts';
5+
import siteConfig from './src/ngmd.config.ts';
26
import {buildLlmsTxt} from './llms-txt.plugin.ts';
37

4-
const {index, full} = buildLlmsTxt(import.meta.dirname, config);
8+
const config: NgmdConfig = {
9+
site: {
10+
name: 'Fixture Docs',
11+
description: 'A fixture site.',
12+
url: 'https://docs.example/',
13+
githubUrl: 'https://github.com/example/docs',
14+
},
15+
nav: [
16+
{
17+
label: 'Start',
18+
items: [
19+
{label: 'Second', href: '/start/second'},
20+
{label: 'First', href: '/start/first'},
21+
{label: 'Hidden', href: '/start/hidden'},
22+
],
23+
},
24+
],
25+
};
26+
27+
const page = (title: string, description: string, body: string, extra = '') =>
28+
`---\ntitle: ${title}\ndescription: ${description}\n${extra}---\n\n# ${title}\n\n${body}\n`;
29+
30+
let root: string;
31+
let index: string;
32+
let full: string;
33+
34+
beforeAll(() => {
35+
root = mkdtempSync(join(tmpdir(), 'llms-txt-'));
36+
mkdirSync(join(root, 'src/content/start'), {recursive: true});
37+
writeFileSync(join(root, 'src/content/start/first.md'), page('First', 'The first page.', 'One.'));
38+
writeFileSync(
39+
join(root, 'src/content/start/second.md'),
40+
page('Second', 'The second page.', 'Two.'),
41+
);
42+
writeFileSync(
43+
join(root, 'src/content/start/hidden.md'),
44+
page('Hidden', 'Not indexed.', 'Secret.', 'noIndex: true\n'),
45+
);
46+
writeFileSync(join(root, 'src/content/extra.md'), page('Extra', 'Not in the sidebar.', 'Three.'));
47+
({index, full} = buildLlmsTxt(root, config));
48+
});
49+
50+
afterAll(() => rmSync(root, {recursive: true, force: true}));
551

652
describe('llms.txt', () => {
753
it('starts with the site name and summary', () => {
8-
expect(index.startsWith(`# ${config.site.name}\n\n> ${config.site.description}\n`)).toBe(true);
9-
expect(full.startsWith(`# ${config.site.name}\n`)).toBe(true);
54+
expect(index.startsWith('# Fixture Docs\n\n> A fixture site.\n')).toBe(true);
55+
expect(full.startsWith('# Fixture Docs\n')).toBe(true);
1056
});
1157

1258
it('links each sidebar page to its markdown route with its description, in sidebar order', () => {
13-
const first = config.nav[0];
14-
expect(index).toContain(`## ${first.label}`);
15-
expect(index).toMatch(
16-
/- \[Quick start\]\(https:\/\/pangular-inspector\.dev\/getting-started\/quick-start\.md\): \S/,
59+
const second = index.indexOf(
60+
'- [Second](https://docs.example/start/second.md): The second page.',
1761
);
18-
const positions = first.items
19-
.map((item) => index.indexOf(`${config.site.url}${item.href}.md`))
20-
.filter((at) => at >= 0);
21-
expect(positions).toEqual([...positions].sort((a, b) => a - b));
62+
const first = index.indexOf('- [First](https://docs.example/start/first.md): The first page.');
63+
expect(index).toContain('## Start');
64+
expect(second).toBeGreaterThan(-1);
65+
expect(first).toBeGreaterThan(second);
66+
});
67+
68+
it('lists content pages missing from the sidebar under Optional', () => {
69+
expect(index).toMatch(/## Optional\n\n- \[Extra\]\(https:\/\/docs\.example\/extra\.md\)/);
2270
});
2371

2472
it('leaves out noIndex pages and keeps page bodies without frontmatter', () => {
25-
expect(index).not.toContain('/contributing/kitchen-sink.md');
26-
expect(full).not.toContain('<!-- https://pangular-inspector.dev/contributing/kitchen-sink -->');
27-
expect(full).toContain(
28-
'<!-- https://pangular-inspector.dev/getting-started/troubleshooting -->',
29-
);
30-
expect(full).not.toContain('title: Troubleshooting\n');
31-
expect(full).toContain('\n\n# Troubleshooting\n');
73+
expect(index).not.toContain('hidden');
74+
expect(full).not.toContain('Secret.');
75+
expect(full).toContain('<!-- https://docs.example/start/first -->\n\n# First\n\nOne.');
76+
expect(full).not.toContain('description: The first page.');
77+
});
78+
79+
it('builds the real site without errors', () => {
80+
const site = buildLlmsTxt(import.meta.dirname, siteConfig);
81+
expect(site.index.startsWith(`# ${siteConfig.site.name}\n`)).toBe(true);
82+
expect(site.index).toContain(`## ${siteConfig.nav[0].label}`);
3283
});
3384
});

‎apps/docs/llms-txt.plugin.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,13 @@ export function llmsTxtPlugin(config: NgmdConfig): Plugin {
116116
server.middlewares.use((req, res, next) => {
117117
const path = req.url?.split('?')[0];
118118
if (path !== '/llms.txt' && path !== '/llms-full.txt') return next();
119-
const {index, full} = buildLlmsTxt(root, config);
120-
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
121-
res.end(path === '/llms.txt' ? index : full);
119+
try {
120+
const {index, full} = buildLlmsTxt(root, config);
121+
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
122+
res.end(path === '/llms.txt' ? index : full);
123+
} catch (err) {
124+
next(err);
125+
}
122126
});
123127
},
124128
generateBundle() {

‎apps/docs/src/content/agents/recipes.md‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: Prompts to paste into Claude Code, Cursor or Copilot for common deb
99

1010
# Recipes for agents
1111

12-
Each recipe is a prompt you paste into your coding agent, the agent tools it leads to, and what to check in the answer. The prompts work in any client that is connected to the [MCP server](./mcp-server.md), such as Claude Code, Cursor or VS Code with Copilot. Clients see the tools as `pangular_<name>`. See [Names](./tools.md#names).
12+
Each recipe is a prompt you paste into your coding agent, the agent tools it leads to, and what to check in the answer. The prompts work in any client that is connected to the HTTP endpoint of the [MCP server](./mcp-server.md), such as Claude Code, Cursor or VS Code with Copilot. The stdio server leaves out the tools that read the running app, so these recipes need HTTP. See [What stdio can answer](./mcp-server.md#what-stdio-can-answer). Clients see the tools as `pangular_<name>`. See [Names](./tools.md#names).
1313

1414
Keep the app open in a development build with the overlay loaded while the agent works. The live tools read the pages that report to the server. If several tabs are open, ask the agent to call `list-pages` first and name the tab.
1515

@@ -24,12 +24,13 @@ The checkout form won't submit. Use the Pangular tools to find which fields make
2424
invalid and why, fix the cause in the code, then show me the form is valid.
2525
```
2626

27-
| Step | Tool |
28-
| --------------------------- | ------------------------------------------------------------- |
29-
| Find the invalid fields | `explain-invalid-forms` |
30-
| Look at one field | `explain-field` with `form` and `path` |
31-
| See why submit does nothing | `explain-submit` |
32-
| Prove the fix | `list-form-changes` for a marker, then `explain-form-changes` |
27+
| Step | Tool |
28+
| ---------------------------- | ----------------------------------------------------- |
29+
| Keep a marker before the fix | `list-form-changes`, which returns the current marker |
30+
| Find the invalid fields | `explain-invalid-forms` |
31+
| Look at one field | `explain-field` with `form` and `path` |
32+
| See why submit does nothing | `explain-submit` |
33+
| Prove the fix | `explain-form-changes` with the marker as `after` |
3334

3435
Check that the answer names the failing validator and its message for each field, not only that the form is invalid. Values that look secret stay redacted. See [Forms](./tools.md#forms).
3536

@@ -62,7 +63,7 @@ Angular looked for it and why no injector provided it, then fix the providers.
6263
| Walk the lookup path | `explain-injection` with the owner as `injector` and the token |
6364
| Read the providers at a level | `inspect-providers` |
6465

65-
`explain-error` adds the missing provider explainer, and its owner id works as the `injector` of `explain-injection`. Check that the answer marks each injector on the path as **provides it**, **not provided** or **hidden**. See [explain-injection](./tools.md#explain-injection).
66+
`explain-error` adds the missing provider explainer, and its owner id works as the `injector` of `explain-injection`. If it says **Component: not found**, for example when a routed component fails before it is in the tree, read the stack of the error for the class that injects the token, pass that class name as `injector`, and call `scan-providers` to see where the source provides the token. Check that the answer marks each injector on the path as **provides it**, **not provided** or **hidden**. See [explain-injection](./tools.md#explain-injection).
6667

6768
## Find wasted change detection
6869

@@ -86,7 +87,7 @@ Before you change anything, take a Pangular audit of this page as a baseline. Af
8687
fix, repeat the same steps, run the audit again and compare the two.
8788
```
8889

89-
The agent calls `audit` with `session: "before"`, makes the change, repeats the same steps in the app and calls `audit` with `session: "after"`, which compares the two. [Inspect, fix and verify](../guides/inspect-fix-verify.md) walks through the loop, and the `verify-fix` prompt asks for it in one step.
90+
The agent calls `audit` with `session: "before"`, makes the change, repeats the same steps in the app and calls `audit` with `session: "after"`, which compares the two. [Inspect, fix and verify](../guides/inspect-fix-verify.md) walks through the loop. The `verify-fix` prompt is a lighter check without the audit: it repeats the calls that showed the problem, compares the answers and looks for new errors.
9091

9192
## Where to next
9293

‎apps/docs/src/content/getting-started/angular-native.md‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,30 @@ bun add @pangular-inspector/devtools
5858

5959
The overlay needs a `WebSocket` global and a standards-compliant `URL`. React Native provides `WebSocket`, and Expo provides `URL`, so an Expo app needs nothing more.
6060

61-
React Native's own `URL` is read-only, and the client sets the `protocol` of the socket URL. In a bare React Native app, add a polyfill such as `react-native-url-polyfill` and import it first in `src/main.ts`.
61+
React Native's own `URL` is read-only, and the client sets the `protocol` of the socket URL. In a bare React Native app, install a polyfill such as `react-native-url-polyfill`:
62+
63+
```bash group="url-polyfill" name="pnpm" image="https://cdn.simpleicons.org/pnpm/F69220" active
64+
pnpm add react-native-url-polyfill
65+
```
66+
67+
```bash group="url-polyfill" name="npm" image="https://cdn.simpleicons.org/npm/CB3837"
68+
npm install react-native-url-polyfill
69+
```
70+
71+
```bash group="url-polyfill" name="yarn" image="https://cdn.simpleicons.org/yarn/2C8EBB"
72+
yarn add react-native-url-polyfill
73+
```
74+
75+
```bash group="url-polyfill" name="bun" image="https://bun.sh/logo.svg"
76+
bun add react-native-url-polyfill
77+
```
78+
79+
Then import it first in `src/main.ts`, above the imports of the next sample:
80+
81+
```ts
82+
// src/main.ts
83+
import 'react-native-url-polyfill/auto';
84+
```
6285

6386
### Start the overlay
6487

‎apps/docs/src/content/getting-started/features.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Features
3-
description: A tour of every tab in the panel, with a screenshot and what to open it for, plus what works outside the panel.
3+
description: A tour of every tab in the panel and what to open it for, with screenshots of most tabs, plus what works outside the panel.
44
---
55

66
<ngmd-hero title="Features" gradient>

‎apps/docs/src/content/getting-started/installation.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ The devtools ship as one npm package, `@pangular-inspector/devtools`. It contain
3131

3232
## Supported setups
3333

34-
Every setup has a server part, which serves the panel, and the [overlay](./overlay.md), which sends live data from your page. Find your app in the table, then follow its page.
34+
Every setup has a server part, which serves the panel. To see live data from a page, the page also runs the [overlay](./overlay.md). The standalone CLI on its own reads only your source files and needs no overlay. Find your app in the table, then follow its page.
3535

3636
| Your app | Dev server or builder | Server part | Steps | Install check |
3737
| ---------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------- | ------ | ------------- |

‎apps/docs/src/content/getting-started/introduction.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The same tool runs in several places. It is built with *Devframe, so one definit
2121

2222
### Live inspectors
2323

24-
These tabs read the running page through Angular's debug API. They need a development build. [Features](./features.md) shows each tab with a screenshot.
24+
These tabs read the running page through Angular's debug API. They need a development build. [Features](./features.md) walks through each tab, with screenshots of most of them.
2525

2626
<ngmd-card-grid columns="2">
2727
<ngmd-card icon="layers" title="Components" link="/inspectors/components" cta="Components">

‎apps/docs/src/content/getting-started/nativescript.md‎

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,30 @@ import '@valor/nativescript-websockets';
6767

6868
### Start the overlay
6969

70-
```ts {2,4-6}
70+
```ts {7,11-13}
7171
// src/main.ts
72+
import {
73+
bootstrapApplication,
74+
provideNativeScriptRouter,
75+
runNativeScriptAngularApp,
76+
} from '@nativescript/angular';
7277
import {initNativeScriptOverlay} from '@pangular-inspector/devtools/overlay-nativescript';
78+
import {routes} from './app/app.routes';
79+
import {AppComponent} from './app/app.component';
7380

7481
if (__DEV__) {
7582
initNativeScriptOverlay();
7683
}
84+
85+
runNativeScriptAngularApp({
86+
appModuleBootstrap: () =>
87+
bootstrapApplication(AppComponent, {
88+
providers: [provideNativeScriptRouter(routes)],
89+
}),
90+
});
7791
```
7892

79-
Call it before `runNativeScriptAngularApp()`. The injector inspector relies on *Angular's injector profiler, which *Angular only wires while it creates the platform. See [Options](#options) for `baseURL`, `intervalMs` and `retryMs`.
93+
Call it before `runNativeScriptAngularApp()`, as above. The injector inspector relies on *Angular's injector profiler, which *Angular only wires while it creates the platform. See [Options](#options) for `baseURL`, `intervalMs` and `retryMs`.
8094

8195
### Where the overlay connects
8296

@@ -206,10 +220,17 @@ The demo maps `@pangular-inspector/devtools/*` to the package's build output in
206220
```bash
207221
pnpm devtools:build-pkg
208222
pnpm devtools:nativescript
209-
cd examples/nativescript && npm install && ns debug ios --no-hmr
210223
```
211224

212-
`pnpm devtools:nativescript` starts the devtools server on `localhost`, scanning `examples/nativescript/src`. For a physical device, `pnpm devtools:nativescript:device` listens on every interface instead, with the same warning as above.
225+
`pnpm devtools:nativescript` starts the devtools server on `localhost`, scanning `examples/nativescript/src`, and keeps running. In a second terminal, install and start the app:
226+
227+
```bash
228+
cd examples/nativescript
229+
npm install
230+
ns debug ios --no-hmr
231+
```
232+
233+
For a physical device, `pnpm devtools:nativescript:device` listens on every interface instead, with the same warning as above.
213234

214235
## Troubleshooting
215236

‎apps/docs/src/content/getting-started/vite.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,13 @@ export const appConfig: ApplicationConfig = {
232232

233233
## Trace server renders
234234

235-
To fill the **SSR requests** table in the **SSR & HTTP** tab, add a Nitro server middleware that traces each page render. Analog runs files in `src/server/middleware` before it renders the page, on the dev server too:
235+
To fill the **SSR requests** table in the **SSR & HTTP** tab, add a Nitro server middleware that traces each page render. Analog runs files in `src/server/middleware` before it renders the page, on the dev server too. The middleware imports `h3`, so add `h3` 1 to your app first, the version Analog's server uses:
236+
237+
```bash
238+
pnpm add h3@^1.15.0
239+
```
240+
241+
Then add the middleware:
236242

237243
```ts
238244
// src/server/middleware/pangular-ssr.ts

‎apps/docs/src/nav-badges.spec.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ describe('nav badges', () => {
1212
expect(compareVersions('1.0.0', '1.2.0')).toBeLessThan(0);
1313
expect(compareVersions('1.2.0', '1.2.0')).toBe(0);
1414
expect(compareVersions('1.10.0', '1.2.0')).toBeGreaterThan(0);
15-
expect(compareVersions('1.2.0-rc.1', '1.2.0')).toBe(0);
15+
expect(compareVersions('1.2.0-rc.1', '1.2.0')).toBeLessThan(0);
16+
expect(compareVersions('1.2.0-rc.2', '1.2.0-rc.10')).toBeLessThan(0);
17+
expect(compareVersions('1.2.0+build.5', '1.2.0')).toBe(0);
1618
expect(compareVersions('next', '1.2.0')).toBeNaN();
1719
});
1820

1921
it('shows a badge while the package version is older than until', () => {
2022
expect(activeBadge({status: 'new', until: '1.2.0'}, '1.1.4')).toBe('new');
23+
expect(activeBadge({status: 'new', until: '1.2.0'}, '1.2.0-rc.1')).toBe('new');
2124
expect(activeBadge({status: 'new', until: '1.2.0'}, '1.2.0')).toBeNull();
2225
expect(activeBadge({status: 'updated', until: '1.2.0'}, '2.0.0')).toBeNull();
2326
});

0 commit comments

Comments
 (0)