svelte-docsmith 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/config.d.ts +27 -0
  2. package/dist/config.js +9 -1
  3. package/dist/generate-llms.d.ts +31 -0
  4. package/dist/generate-llms.js +63 -0
  5. package/dist/index.d.ts +3 -1
  6. package/dist/index.js +5 -0
  7. package/dist/llms.d.ts +11 -0
  8. package/dist/llms.js +4 -0
  9. package/dist/normalize-path.d.ts +6 -0
  10. package/dist/normalize-path.js +8 -0
  11. package/dist/sitemap.d.ts +27 -0
  12. package/dist/sitemap.js +44 -0
  13. package/dist/ui/layouts/copy-page-menu.svelte +113 -0
  14. package/dist/ui/layouts/copy-page-menu.svelte.d.ts +9 -0
  15. package/dist/ui/layouts/docs-header.svelte +1 -1
  16. package/dist/ui/layouts/docs-mobile-header.svelte +1 -1
  17. package/dist/ui/layouts/docs-shell.svelte +83 -9
  18. package/dist/ui/layouts/docs-shell.svelte.d.ts +6 -0
  19. package/dist/ui/layouts/docs-sidebar.svelte +3 -2
  20. package/dist/ui/layouts/prev-next-nav.svelte +9 -2
  21. package/dist/ui/layouts/prev-next-nav.svelte.d.ts +1 -0
  22. package/dist/ui/layouts/seo-head.svelte +2 -1
  23. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  24. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
  25. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  26. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
  27. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-content.svelte +31 -0
  28. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
  29. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  30. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
  31. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-group.svelte +7 -0
  32. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
  33. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-item.svelte +27 -0
  34. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
  35. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-label.svelte +27 -0
  36. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
  37. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  38. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
  39. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  40. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
  41. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  42. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
  43. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  44. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
  45. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
  46. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
  47. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte +20 -0
  48. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +4 -0
  49. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  50. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
  51. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  52. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
  53. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  54. package/dist/ui/shadcn/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
  55. package/dist/ui/shadcn/dropdown-menu/dropdown-menu.svelte +7 -0
  56. package/dist/ui/shadcn/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
  57. package/dist/ui/shadcn/dropdown-menu/index.d.ts +18 -0
  58. package/dist/ui/shadcn/dropdown-menu/index.js +18 -0
  59. package/dist/vite.d.ts +8 -1
  60. package/dist/vite.js +60 -3
  61. package/package.json +7 -4
package/dist/vite.js CHANGED
@@ -12,6 +12,7 @@
12
12
  * 3. The **`?source` transform** powering `LiveExample`: importing
13
13
  * `Component.svelte?source` yields that file's Shiki-highlighted source.
14
14
  */
15
+ import { spawnSync } from 'node:child_process';
15
16
  import fs from 'node:fs';
16
17
  import path from 'node:path';
17
18
  import GithubSlugger from 'github-slugger';
@@ -33,6 +34,8 @@ const CONTENT_SPECIFIER = 'svelte-docsmith/content';
33
34
  const VIRTUAL_CONTENT_ID = '\0svelte-docsmith:content';
34
35
  const SEARCH_SPECIFIER = 'svelte-docsmith/search';
35
36
  const VIRTUAL_SEARCH_ID = '\0svelte-docsmith:search';
37
+ const LLMS_SPECIFIER = 'svelte-docsmith/llms';
38
+ const VIRTUAL_LLMS_ID = '\0svelte-docsmith:llms';
36
39
  const PAGE_NAMES = ['+page.md', '+page.svx'];
37
40
  function isPageFile(file) {
38
41
  return PAGE_NAMES.some((name) => file.endsWith(name));
@@ -138,6 +141,15 @@ function extractToc(source) {
138
141
  }
139
142
  return toc;
140
143
  }
144
+ /** Last git commit date (strict ISO) for a file, or undefined outside a repo. */
145
+ function lastCommitDate(file) {
146
+ const res = spawnSync('git', ['log', '-1', '--format=%cI', '--', file], {
147
+ cwd: path.dirname(file),
148
+ encoding: 'utf-8'
149
+ });
150
+ const date = res.status === 0 ? res.stdout.trim() : '';
151
+ return date || undefined;
152
+ }
141
153
  /**
142
154
  * Walk every nav-worthy page under `contentDir` once: a page is nav-worthy when
143
155
  * its frontmatter has a string `title`. Yields the raw source, parsed
@@ -152,7 +164,7 @@ function* eachTitledPage(contentDir, routesDir) {
152
164
  continue;
153
165
  const dir = path.dirname(file);
154
166
  const url = '/' + path.relative(routesDir, dir).split(path.sep).join('/');
155
- yield { source, front, url, title: front.title };
167
+ yield { source, front, url, title: front.title, file };
156
168
  }
157
169
  }
158
170
  export function collectDocs(contentDir, routesDir) {
@@ -162,13 +174,15 @@ export function collectDocs(contentDir, routesDir) {
162
174
  return [];
163
175
  }
164
176
  const items = [];
165
- for (const { source, front, url, title } of eachTitledPage(contentDir, routesDir)) {
177
+ for (const { source, front, url, title, file } of eachTitledPage(contentDir, routesDir)) {
166
178
  items.push({
167
179
  title,
168
180
  path: url,
169
181
  description: typeof front.description === 'string' ? front.description : undefined,
170
182
  section: typeof front.section === 'string' ? front.section : undefined,
171
183
  order: typeof front.order === 'number' ? front.order : undefined,
184
+ sourcePath: path.relative(process.cwd(), file).split(path.sep).join('/'),
185
+ lastUpdated: lastCommitDate(file),
172
186
  toc: extractToc(source)
173
187
  });
174
188
  }
@@ -202,6 +216,41 @@ export function collectSearchDocs(contentDir, routesDir) {
202
216
  }
203
217
  return docs.sort((a, b) => a.path.localeCompare(b.path));
204
218
  }
219
+ /**
220
+ * The page's markdown body for LLM output: frontmatter and `<script>`/`<style>`
221
+ * blocks removed, everything else (headings, prose, code, component tags) kept,
222
+ * with the frontmatter title prepended as an `h1` (pages start their body at h2).
223
+ */
224
+ function extractLlmsContent(source, title) {
225
+ const body = source
226
+ .replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '')
227
+ .replace(/<script[\s\S]*?<\/script>/gi, '')
228
+ .replace(/<style[\s\S]*?<\/style>/gi, '')
229
+ .trim();
230
+ return `# ${title}\n\n${body}`;
231
+ }
232
+ /**
233
+ * Build the LLM records for every page: title, section, description, and the
234
+ * full markdown content. Served as the `svelte-docsmith/llms` virtual module and
235
+ * consumed server-side by `llms.txt` / `llms-full.txt` routes, so it never ships
236
+ * to the client.
237
+ */
238
+ export function collectLlmsDocs(contentDir, routesDir) {
239
+ if (!fs.existsSync(contentDir))
240
+ return [];
241
+ const docs = [];
242
+ for (const { source, front, url, title } of eachTitledPage(contentDir, routesDir)) {
243
+ docs.push({
244
+ path: url,
245
+ title,
246
+ section: typeof front.section === 'string' ? front.section : undefined,
247
+ order: typeof front.order === 'number' ? front.order : undefined,
248
+ description: typeof front.description === 'string' ? front.description : undefined,
249
+ content: extractLlmsContent(source, title)
250
+ });
251
+ }
252
+ return docs.sort((a, b) => a.path.localeCompare(b.path));
253
+ }
205
254
  function parseFrontmatter(source, file) {
206
255
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(source);
207
256
  if (!match)
@@ -227,6 +276,8 @@ function contentIndexPlugin(options) {
227
276
  return VIRTUAL_CONTENT_ID;
228
277
  if (id === SEARCH_SPECIFIER)
229
278
  return VIRTUAL_SEARCH_ID;
279
+ if (id === LLMS_SPECIFIER)
280
+ return VIRTUAL_LLMS_ID;
230
281
  },
231
282
  load(id) {
232
283
  // Watch each page file (not the directory) so editing frontmatter or
@@ -245,6 +296,12 @@ function contentIndexPlugin(options) {
245
296
  const docs = collectSearchDocs(contentDir, routesDir);
246
297
  return `export const docs = ${JSON.stringify(docs)};\n`;
247
298
  }
299
+ if (id === VIRTUAL_LLMS_ID) {
300
+ for (const file of listPageFiles(contentDir))
301
+ this.addWatchFile(file);
302
+ const docs = collectLlmsDocs(contentDir, routesDir);
303
+ return `export const docs = ${JSON.stringify(docs)};\n`;
304
+ }
248
305
  },
249
306
  configureServer(server) {
250
307
  server.watcher.add(contentDir);
@@ -252,7 +309,7 @@ function contentIndexPlugin(options) {
252
309
  if (!isPageFile(file))
253
310
  return;
254
311
  let invalidated = false;
255
- for (const virtualId of [VIRTUAL_CONTENT_ID, VIRTUAL_SEARCH_ID]) {
312
+ for (const virtualId of [VIRTUAL_CONTENT_ID, VIRTUAL_SEARCH_ID, VIRTUAL_LLMS_ID]) {
256
313
  const mod = server.moduleGraph.getModuleById(virtualId);
257
314
  if (!mod)
258
315
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-docsmith",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "A framework for building beautiful documentation sites with Svelte.",
5
5
  "author": {
6
6
  "name": "George Daskalakis",
@@ -39,6 +39,10 @@
39
39
  "types": "./dist/search.d.ts",
40
40
  "default": "./dist/search.js"
41
41
  },
42
+ "./llms": {
43
+ "types": "./dist/llms.d.ts",
44
+ "default": "./dist/llms.js"
45
+ },
42
46
  "./theme.css": "./dist/theme.css",
43
47
  "./themes/*.css": "./dist/themes/*.css",
44
48
  "./package.json": "./package.json"
@@ -58,6 +62,7 @@
58
62
  },
59
63
  "devDependencies": {
60
64
  "@internationalized/date": "^3.12.2",
65
+ "@lucide/svelte": "^1.24.0",
61
66
  "@sveltejs/adapter-auto": "^7.0.1",
62
67
  "@sveltejs/adapter-vercel": "^6.3.4",
63
68
  "@sveltejs/kit": "^2.69.1",
@@ -81,7 +86,6 @@
81
86
  "dependencies": {
82
87
  "@fontsource-variable/inter": "^5.2.8",
83
88
  "@hbsnow/rehype-sectionize": "^1.0.7",
84
- "@lucide/svelte": "^1.24.0",
85
89
  "@shikijs/transformers": "^3.3.0",
86
90
  "@tailwindcss/typography": "^0.5.16",
87
91
  "bits-ui": "^2.18.1",
@@ -115,7 +119,6 @@
115
119
  "test": "vitest run",
116
120
  "test:coverage": "vitest run --coverage",
117
121
  "test:unit": "vitest run",
118
- "typecheck": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
119
- "size": "size-limit"
122
+ "typecheck": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
120
123
  }
121
124
  }