@farming-labs/svelte 0.0.2-beta.13 → 0.0.2-beta.15

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.
package/dist/content.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * extracts frontmatter, and builds a navigation tree compatible
6
6
  * with @farming-labs/docs DocsConfig.
7
7
  */
8
+ import type { OrderingItem } from "@farming-labs/docs";
8
9
  export interface PageNode {
9
10
  type: "page";
10
11
  name: string;
@@ -44,7 +45,7 @@ export declare function loadDocsContent(contentDir: string, entry?: string): Con
44
45
  /**
45
46
  * Build a navigation tree from a content directory.
46
47
  */
47
- export declare function loadDocsNavTree(contentDir: string, entry?: string): NavTree;
48
+ export declare function loadDocsNavTree(contentDir: string, entry?: string, ordering?: "alphabetical" | "numeric" | OrderingItem[]): NavTree;
48
49
  /**
49
50
  * Flatten a navigation tree into an ordered list of pages.
50
51
  * Useful for computing previous/next page links.
package/dist/content.js CHANGED
@@ -58,7 +58,7 @@ export function loadDocsContent(contentDir, entry = "docs") {
58
58
  /**
59
59
  * Build a navigation tree from a content directory.
60
60
  */
61
- export function loadDocsNavTree(contentDir, entry = "docs") {
61
+ export function loadDocsNavTree(contentDir, entry = "docs", ordering) {
62
62
  const absDir = path.resolve(contentDir);
63
63
  const children = [];
64
64
  const indexPath = findIndex(absDir);
@@ -71,42 +71,87 @@ export function loadDocsNavTree(contentDir, entry = "docs") {
71
71
  icon: data.icon,
72
72
  });
73
73
  }
74
- children.push(...scanDir(absDir, [], entry));
74
+ const rootSlugOrder = Array.isArray(ordering) ? ordering : undefined;
75
+ children.push(...scanDir(absDir, [], entry, ordering, rootSlugOrder));
75
76
  return { name: "Docs", children };
76
77
  }
77
- function scanDir(dir, slugParts, entry) {
78
+ function buildNavNode(dir, name, slugParts, entry, ordering, childSlugOrder) {
79
+ const full = path.join(dir, name);
80
+ if (!fs.statSync(full).isDirectory())
81
+ return null;
82
+ const indexPath = findIndex(full);
83
+ if (!indexPath)
84
+ return null;
85
+ const { data } = matter(fs.readFileSync(indexPath, "utf-8"));
86
+ const slug = [...slugParts, name];
87
+ const url = `/${entry}/${slug.join("/")}`;
88
+ const displayName = data.title ?? name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
89
+ const icon = data.icon;
90
+ const childDirs = fs.readdirSync(full).filter((n) => {
91
+ const p = path.join(full, n);
92
+ return fs.statSync(p).isDirectory() && findIndex(p) !== null;
93
+ });
94
+ if (childDirs.length > 0) {
95
+ return {
96
+ type: "folder",
97
+ name: displayName,
98
+ icon,
99
+ index: { type: "page", name: displayName, url, icon },
100
+ children: scanDir(full, slug, entry, ordering, childSlugOrder),
101
+ };
102
+ }
103
+ return { type: "page", name: displayName, url, icon };
104
+ }
105
+ function scanDir(dir, slugParts, entry, ordering, slugOrder) {
78
106
  if (!fs.existsSync(dir))
79
107
  return [];
80
- const nodes = [];
81
108
  const entries = fs.readdirSync(dir).sort();
82
- for (const name of entries) {
83
- const full = path.join(dir, name);
84
- if (!fs.statSync(full).isDirectory())
85
- continue;
86
- const indexPath = findIndex(full);
87
- if (!indexPath)
88
- continue;
89
- const { data } = matter(fs.readFileSync(indexPath, "utf-8"));
90
- const slug = [...slugParts, name];
91
- const url = `/${entry}/${slug.join("/")}`;
92
- const displayName = data.title ?? name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
93
- const icon = data.icon;
94
- const childDirs = fs.readdirSync(full).filter((n) => {
95
- const p = path.join(full, n);
96
- return fs.statSync(p).isDirectory() && findIndex(p) !== null;
97
- });
98
- if (childDirs.length > 0) {
99
- nodes.push({
100
- type: "folder",
101
- name: displayName,
102
- icon,
103
- index: { type: "page", name: displayName, url, icon },
104
- children: scanDir(full, slug, entry),
105
- });
109
+ if (slugOrder) {
110
+ const nodes = [];
111
+ const slugMap = new Set(slugOrder.map((i) => i.slug));
112
+ for (const item of slugOrder) {
113
+ if (!entries.includes(item.slug))
114
+ continue;
115
+ const node = buildNavNode(dir, item.slug, slugParts, entry, ordering, item.children);
116
+ if (node)
117
+ nodes.push(node);
118
+ }
119
+ for (const name of entries) {
120
+ if (slugMap.has(name))
121
+ continue;
122
+ const node = buildNavNode(dir, name, slugParts, entry, ordering);
123
+ if (node)
124
+ nodes.push(node);
106
125
  }
107
- else {
108
- nodes.push({ type: "page", name: displayName, url, icon });
126
+ return nodes;
127
+ }
128
+ if (ordering === "numeric") {
129
+ const nodes = [];
130
+ for (const name of entries) {
131
+ const full = path.join(dir, name);
132
+ if (!fs.statSync(full).isDirectory())
133
+ continue;
134
+ const indexPath = findIndex(full);
135
+ if (!indexPath)
136
+ continue;
137
+ const { data } = matter(fs.readFileSync(indexPath, "utf-8"));
138
+ const order = typeof data.order === "number" ? data.order : Infinity;
139
+ const node = buildNavNode(dir, name, slugParts, entry, ordering);
140
+ if (node)
141
+ nodes.push({ order, node });
109
142
  }
143
+ nodes.sort((a, b) => {
144
+ if (a.order === b.order)
145
+ return 0;
146
+ return a.order - b.order;
147
+ });
148
+ return nodes.map((n) => n.node);
149
+ }
150
+ const nodes = [];
151
+ for (const name of entries) {
152
+ const node = buildNavNode(dir, name, slugParts, entry, ordering);
153
+ if (node)
154
+ nodes.push(node);
110
155
  }
111
156
  return nodes;
112
157
  }
package/dist/server.js CHANGED
@@ -49,7 +49,7 @@ function stripMarkdownText(content) {
49
49
  .replace(/\n{3,}/g, "\n\n")
50
50
  .trim();
51
51
  }
52
- function navTreeFromMap(contentMap, dirPrefix, entry) {
52
+ function navTreeFromMap(contentMap, dirPrefix, entry, ordering) {
53
53
  const dirs = [];
54
54
  for (const key of Object.keys(contentMap)) {
55
55
  if (!key.startsWith(dirPrefix))
@@ -74,8 +74,10 @@ function navTreeFromMap(contentMap, dirPrefix, entry) {
74
74
  title: data.title ?? fallbackTitle,
75
75
  url,
76
76
  icon: data.icon,
77
+ order: typeof data.order === "number" ? data.order : Infinity,
77
78
  });
78
79
  }
80
+ // Default sort: depth first, then by ordering strategy
79
81
  dirs.sort((a, b) => {
80
82
  if (a.parts.length !== b.parts.length)
81
83
  return a.parts.length - b.parts.length;
@@ -91,8 +93,19 @@ function navTreeFromMap(contentMap, dirPrefix, entry) {
91
93
  icon: rootInfo.icon,
92
94
  });
93
95
  }
96
+ function findSlugOrder(parentParts) {
97
+ if (!Array.isArray(ordering))
98
+ return undefined;
99
+ let items = ordering;
100
+ for (const part of parentParts) {
101
+ const found = items.find((i) => i.slug === part);
102
+ if (!found?.children)
103
+ return undefined;
104
+ items = found.children;
105
+ }
106
+ return items;
107
+ }
94
108
  function buildLevel(parentParts) {
95
- const nodes = [];
96
109
  const depth = parentParts.length;
97
110
  const directChildren = dirs.filter((d) => {
98
111
  if (d.parts.length !== depth + 1)
@@ -103,6 +116,49 @@ function navTreeFromMap(contentMap, dirPrefix, entry) {
103
116
  }
104
117
  return true;
105
118
  });
119
+ const slugOrder = findSlugOrder(parentParts);
120
+ if (slugOrder) {
121
+ const slugMap = new Set(slugOrder.map((i) => i.slug));
122
+ const ordered = [];
123
+ for (const item of slugOrder) {
124
+ const match = directChildren.find((d) => d.parts[depth] === item.slug);
125
+ if (match)
126
+ ordered.push(match);
127
+ }
128
+ for (const child of directChildren) {
129
+ if (!slugMap.has(child.parts[depth]))
130
+ ordered.push(child);
131
+ }
132
+ const nodes = [];
133
+ for (const child of ordered) {
134
+ const hasGrandChildren = dirs.some((d) => {
135
+ if (d.parts.length <= child.parts.length)
136
+ return false;
137
+ return child.parts.every((p, i) => d.parts[i] === p);
138
+ });
139
+ if (hasGrandChildren) {
140
+ nodes.push({
141
+ type: "folder",
142
+ name: child.title,
143
+ icon: child.icon,
144
+ index: { type: "page", name: child.title, url: child.url, icon: child.icon },
145
+ children: buildLevel(child.parts),
146
+ });
147
+ }
148
+ else {
149
+ nodes.push({ type: "page", name: child.title, url: child.url, icon: child.icon });
150
+ }
151
+ }
152
+ return nodes;
153
+ }
154
+ if (ordering === "numeric") {
155
+ directChildren.sort((a, b) => {
156
+ if (a.order === b.order)
157
+ return 0;
158
+ return a.order - b.order;
159
+ });
160
+ }
161
+ const nodes = [];
106
162
  for (const child of directChildren) {
107
163
  const hasGrandChildren = dirs.some((d) => {
108
164
  if (d.parts.length <= child.parts.length)
@@ -206,6 +262,7 @@ export function createDocsServer(config = {}) {
206
262
  const preloaded = config._preloadedContent;
207
263
  const contentDirRel = config.contentDir ?? entry;
208
264
  const dirPrefix = `/${contentDirRel}/`;
265
+ const ordering = config.ordering;
209
266
  const aiConfig = config.ai ?? {};
210
267
  // Allow top-level apiKey as a shorthand
211
268
  if (config.apiKey && !aiConfig.apiKey) {
@@ -214,8 +271,8 @@ export function createDocsServer(config = {}) {
214
271
  // ─── Unified load (tree + page content in one call) ────────
215
272
  async function load(event) {
216
273
  const tree = preloaded
217
- ? navTreeFromMap(preloaded, dirPrefix, entry)
218
- : loadDocsNavTree(contentDir, entry);
274
+ ? navTreeFromMap(preloaded, dirPrefix, entry, ordering)
275
+ : loadDocsNavTree(contentDir, entry, ordering);
219
276
  const flatPages = flattenNavTree(tree);
220
277
  const urlPrefix = new RegExp(`^/${entry}/?`);
221
278
  const slug = event.url.pathname.replace(urlPrefix, "");
@@ -379,6 +436,7 @@ export function createDocsServer(config = {}) {
379
436
  }), { status: 404, headers: { "Content-Type": "application/json" } });
380
437
  }
381
438
  const resolvedKey = aiConfig.apiKey ??
439
+ (typeof import.meta !== "undefined" ? import.meta.env?.OPENAI_API_KEY : undefined) ??
382
440
  (typeof process !== "undefined" ? process.env?.OPENAI_API_KEY : undefined);
383
441
  if (!resolvedKey) {
384
442
  return new Response(JSON.stringify({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/svelte",
3
- "version": "0.0.2-beta.13",
3
+ "version": "0.0.2-beta.15",
4
4
  "description": "SvelteKit adapter for @farming-labs/docs — content loading and navigation utilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,7 +50,7 @@
50
50
  "devDependencies": {
51
51
  "@types/node": "^22.10.0",
52
52
  "typescript": "^5.9.3",
53
- "@farming-labs/docs": "0.0.2-beta.13"
53
+ "@farming-labs/docs": "0.0.2-beta.15"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@farming-labs/docs": "*"