@farming-labs/nuxt 0.0.38 → 0.0.44

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 (65) hide show
  1. package/dist/api-reference.d.ts +3 -0
  2. package/dist/api-reference.d.ts.map +1 -0
  3. package/dist/api-reference.js +21 -0
  4. package/dist/api-reference.js.map +1 -0
  5. package/dist/docs/src/api-reference.d.ts +27 -0
  6. package/dist/docs/src/api-reference.d.ts.map +1 -0
  7. package/dist/docs/src/api-reference.js +594 -0
  8. package/dist/docs/src/api-reference.js.map +1 -0
  9. package/dist/docs/src/create-theme.d.ts +74 -0
  10. package/dist/docs/src/create-theme.d.ts.map +1 -0
  11. package/dist/docs/src/create-theme.js +86 -0
  12. package/dist/docs/src/create-theme.js.map +1 -0
  13. package/dist/docs/src/define-docs.d.ts +6 -0
  14. package/dist/docs/src/define-docs.d.ts.map +1 -0
  15. package/dist/docs/src/define-docs.js +27 -0
  16. package/dist/docs/src/define-docs.js.map +1 -0
  17. package/dist/docs/src/i18n.d.ts +15 -0
  18. package/dist/docs/src/i18n.d.ts.map +1 -0
  19. package/dist/docs/src/i18n.js +48 -0
  20. package/dist/docs/src/i18n.js.map +1 -0
  21. package/dist/docs/src/index.d.ts +16 -0
  22. package/dist/docs/src/index.d.ts.map +1 -0
  23. package/dist/docs/src/index.js +14 -0
  24. package/dist/docs/src/index.js.map +1 -0
  25. package/dist/docs/src/metadata.d.ts +24 -0
  26. package/dist/docs/src/metadata.d.ts.map +1 -0
  27. package/dist/docs/src/metadata.js +90 -0
  28. package/dist/docs/src/metadata.js.map +1 -0
  29. package/dist/docs/src/server.d.ts +3 -0
  30. package/dist/docs/src/server.d.ts.map +1 -0
  31. package/dist/docs/src/server.js +2 -0
  32. package/dist/docs/src/server.js.map +1 -0
  33. package/dist/docs/src/types.d.ts +1344 -0
  34. package/dist/docs/src/types.d.ts.map +1 -0
  35. package/dist/docs/src/types.js +6 -0
  36. package/dist/docs/src/types.js.map +1 -0
  37. package/dist/docs/src/utils.d.ts +6 -0
  38. package/dist/docs/src/utils.d.ts.map +1 -0
  39. package/dist/docs/src/utils.js +32 -0
  40. package/dist/docs/src/utils.js.map +1 -0
  41. package/dist/nuxt/src/api-reference.d.ts +3 -0
  42. package/dist/nuxt/src/api-reference.d.ts.map +1 -0
  43. package/dist/nuxt/src/api-reference.js +20 -0
  44. package/dist/nuxt/src/api-reference.js.map +1 -0
  45. package/dist/nuxt/src/content.d.ts +54 -0
  46. package/dist/nuxt/src/content.d.ts.map +1 -0
  47. package/dist/nuxt/src/content.js +202 -0
  48. package/dist/nuxt/src/content.js.map +1 -0
  49. package/dist/nuxt/src/index.d.ts +11 -0
  50. package/dist/nuxt/src/index.d.ts.map +1 -0
  51. package/dist/nuxt/src/index.js +11 -0
  52. package/dist/nuxt/src/index.js.map +1 -0
  53. package/dist/nuxt/src/markdown.d.ts +18 -0
  54. package/dist/nuxt/src/markdown.d.ts.map +1 -0
  55. package/dist/nuxt/src/markdown.js +277 -0
  56. package/dist/nuxt/src/markdown.js.map +1 -0
  57. package/dist/nuxt/src/server.d.ts +87 -0
  58. package/dist/nuxt/src/server.d.ts.map +1 -0
  59. package/dist/nuxt/src/server.js +726 -0
  60. package/dist/nuxt/src/server.js.map +1 -0
  61. package/dist/server.d.ts +3 -2
  62. package/dist/server.d.ts.map +1 -1
  63. package/dist/server.js +4 -2
  64. package/dist/server.js.map +1 -1
  65. package/package.json +9 -2
@@ -0,0 +1,3 @@
1
+ import type { DocsConfig } from "@farming-labs/docs";
2
+ export declare function defineApiReferenceHandler(config: DocsConfig & Record<string, any>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Response>>;
3
+ //# sourceMappingURL=api-reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-reference.d.ts","sourceRoot":"","sources":["../src/api-reference.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,kFAmBjF"}
@@ -0,0 +1,21 @@
1
+ import { buildApiReferenceHtmlDocument, resolveApiReferenceConfig, } from "@farming-labs/docs/server";
2
+ import { eventHandler } from "h3";
3
+ export function defineApiReferenceHandler(config) {
4
+ return eventHandler(async () => {
5
+ const apiReference = resolveApiReferenceConfig(config.apiReference);
6
+ if (!apiReference.enabled) {
7
+ return new Response("Not Found", { status: 404 });
8
+ }
9
+ const rootDir = typeof config.rootDir === "string" ? config.rootDir : process.cwd();
10
+ const html = buildApiReferenceHtmlDocument(config, {
11
+ framework: "nuxt",
12
+ rootDir,
13
+ });
14
+ return new Response(html, {
15
+ headers: {
16
+ "Content-Type": "text/html; charset=utf-8",
17
+ },
18
+ });
19
+ });
20
+ }
21
+ //# sourceMappingURL=api-reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-reference.js","sourceRoot":"","sources":["../src/api-reference.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC,MAAM,UAAU,yBAAyB,CAAC,MAAwC;IAChF,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;QAC7B,MAAM,YAAY,GAAG,yBAAyB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACpE,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACpF,MAAM,IAAI,GAAG,6BAA6B,CAAC,MAAM,EAAE;YACjD,SAAS,EAAE,MAAM;YACjB,OAAO;SACR,CAAC,CAAC;QAEH,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;YACxB,OAAO,EAAE;gBACP,cAAc,EAAE,0BAA0B;aAC3C;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { ApiReferenceConfig, DocsConfig } from "./types.js";
2
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS" | "HEAD";
3
+ export type ApiReferenceFramework = "next" | "tanstack-start" | "sveltekit" | "astro" | "nuxt";
4
+ export interface ApiReferenceRoute {
5
+ title: string;
6
+ summary: string;
7
+ description?: string;
8
+ routePath: string;
9
+ sourceFile: string;
10
+ methods: HttpMethod[];
11
+ tag: string;
12
+ parameters: Array<Record<string, unknown>>;
13
+ }
14
+ interface BuildApiReferenceOptions {
15
+ framework: ApiReferenceFramework;
16
+ rootDir?: string;
17
+ }
18
+ interface BuildApiReferenceHtmlOptions extends BuildApiReferenceOptions {
19
+ title?: string;
20
+ }
21
+ export declare function resolveApiReferenceConfig(value: DocsConfig["apiReference"]): Required<ApiReferenceConfig>;
22
+ export declare function buildApiReferencePageTitle(config: DocsConfig, title?: string): string;
23
+ export declare function buildApiReferenceScalarCss(config: DocsConfig): string;
24
+ export declare function buildApiReferenceOpenApiDocument(config: DocsConfig, options: BuildApiReferenceOptions): Record<string, unknown>;
25
+ export declare function buildApiReferenceHtmlDocument(config: DocsConfig, options: BuildApiReferenceHtmlOptions): string;
26
+ export {};
27
+ //# sourceMappingURL=api-reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-reference.d.ts","sourceRoot":"","sources":["../../../../docs/src/api-reference.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AAE5E,KAAK,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnF,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,gBAAgB,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;AAE/F,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5C;AAED,UAAU,wBAAwB;IAChC,SAAS,EAAE,qBAAqB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,4BAA6B,SAAQ,wBAAwB;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAeD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAChC,QAAQ,CAAC,kBAAkB,CAAC,CAyB9B;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,SAAkB,GAAG,MAAM,CAI9F;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAkJrE;AAED,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmBzB;AAED,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,4BAA4B,GACpC,MAAM,CA8BR"}
@@ -0,0 +1,594 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { basename, join, relative } from "node:path";
3
+ import { getHtmlDocument } from "@scalar/core/libs/html-rendering";
4
+ const NEXT_ROUTE_FILE_RE = /^route\.(ts|tsx|js|jsx)$/;
5
+ const SVELTE_ROUTE_FILE_RE = /^\+server\.(ts|js)$/;
6
+ const ASTRO_ROUTE_FILE_RE = /^[^.].*\.(ts|js|mts|mjs)$/;
7
+ const NUXT_ROUTE_FILE_RE = /^[^.].*\.(ts|js|mts|mjs)$/;
8
+ const TANSTACK_ROUTE_FILE_RE = /\.(ts|tsx|js|jsx)$/;
9
+ const METHOD_RE = /export\s+(?:async\s+function|function|const)\s+(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD|ALL)\b/g;
10
+ const METHOD_NAMES = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"];
11
+ function normalizePathSegment(value) {
12
+ return value.replace(/^\/+|\/+$/g, "");
13
+ }
14
+ export function resolveApiReferenceConfig(value) {
15
+ if (value === true) {
16
+ return {
17
+ enabled: true,
18
+ path: "api-reference",
19
+ routeRoot: "api",
20
+ exclude: [],
21
+ };
22
+ }
23
+ if (!value) {
24
+ return {
25
+ enabled: false,
26
+ path: "api-reference",
27
+ routeRoot: "api",
28
+ exclude: [],
29
+ };
30
+ }
31
+ return {
32
+ enabled: value.enabled !== false,
33
+ path: normalizePathSegment(value.path ?? "api-reference"),
34
+ routeRoot: normalizePathSegment(value.routeRoot ?? "api") || "api",
35
+ exclude: normalizeApiReferenceExcludes(value.exclude),
36
+ };
37
+ }
38
+ export function buildApiReferencePageTitle(config, title = "API Reference") {
39
+ const template = config.metadata?.titleTemplate;
40
+ if (!template)
41
+ return title;
42
+ return template.replace("%s", title);
43
+ }
44
+ export function buildApiReferenceScalarCss(config) {
45
+ const theme = resolveTheme(config);
46
+ const colors = theme?.ui?.colors;
47
+ const typography = theme?.ui?.typography?.font?.style;
48
+ const layout = theme?.ui?.layout;
49
+ const primary = colors?.primary ?? "#6366f1";
50
+ const border = colors?.border ?? "#2a2a2a";
51
+ const muted = colors?.muted ?? "#64748b";
52
+ const background = colors?.background ?? "#ffffff";
53
+ const card = colors?.card ?? background;
54
+ const foreground = colors?.foreground ?? "#1b1b1b";
55
+ const sidebarWidth = layout?.sidebarWidth ?? 280;
56
+ const sans = typography?.sans ?? '"Geist", "Inter", "Segoe UI", sans-serif';
57
+ const mono = typography?.mono ?? '"Geist Mono", "SFMono-Regular", "Menlo", monospace';
58
+ return `
59
+ :root {
60
+ --scalar-font: ${sans};
61
+ --scalar-font-code: ${mono};
62
+ --scalar-theme-primary: ${primary};
63
+ --scalar-theme-border: ${border};
64
+ --scalar-theme-muted: ${muted};
65
+ --scalar-theme-background: ${background};
66
+ --scalar-theme-card: ${card};
67
+ --scalar-theme-foreground: ${foreground};
68
+ }
69
+
70
+ .dark-mode {
71
+ --scalar-background-1: color-mix(in srgb, #0b0c0b 98%, var(--scalar-theme-primary) 2%);
72
+ --scalar-background-2: color-mix(in srgb, #111311 96%, var(--scalar-theme-primary) 4%);
73
+ --scalar-background-3: color-mix(in srgb, #171917 95%, var(--scalar-theme-primary) 5%);
74
+ --scalar-color-1: rgba(255, 255, 255, 0.96);
75
+ --scalar-color-2: rgba(255, 255, 255, 0.72);
76
+ --scalar-color-3: rgba(255, 255, 255, 0.5);
77
+ --scalar-color-accent: var(--scalar-theme-primary);
78
+ --scalar-sidebar-color-active: var(--scalar-theme-primary);
79
+ --scalar-sidebar-item-active-background: color-mix(
80
+ in srgb,
81
+ var(--scalar-theme-primary) 7%,
82
+ transparent
83
+ );
84
+ --scalar-border-color: color-mix(
85
+ in srgb,
86
+ var(--scalar-theme-border) 22%,
87
+ rgba(255, 255, 255, 0.032)
88
+ );
89
+ --scalar-button-1: var(--scalar-theme-primary);
90
+ --scalar-button-1-color: #ffffff;
91
+ --scalar-button-1-hover: color-mix(in srgb, var(--scalar-theme-primary) 88%, white 12%);
92
+ }
93
+
94
+ .light-mode {
95
+ --scalar-background-1: var(--scalar-theme-background);
96
+ --scalar-background-2: color-mix(in srgb, var(--scalar-theme-card) 92%, white 8%);
97
+ --scalar-background-3: color-mix(in srgb, var(--scalar-theme-card) 84%, black 4%);
98
+ --scalar-color-1: var(--scalar-theme-foreground);
99
+ --scalar-color-2: var(--scalar-theme-muted);
100
+ --scalar-color-3: color-mix(in srgb, var(--scalar-theme-muted) 78%, white 22%);
101
+ --scalar-color-accent: var(--scalar-theme-primary);
102
+ --scalar-sidebar-color-active: var(--scalar-theme-primary);
103
+ --scalar-sidebar-item-active-background: color-mix(
104
+ in srgb,
105
+ var(--scalar-theme-primary) 5%,
106
+ transparent
107
+ );
108
+ --scalar-border-color: color-mix(in srgb, var(--scalar-theme-border) 42%, white 58%);
109
+ --scalar-button-1: var(--scalar-theme-primary);
110
+ --scalar-button-1-color: #ffffff;
111
+ --scalar-button-1-hover: color-mix(in srgb, var(--scalar-theme-primary) 88%, black 12%);
112
+ }
113
+
114
+ body {
115
+ background: var(--scalar-background-1);
116
+ }
117
+
118
+ .t-doc__sidebar {
119
+ width: min(${sidebarWidth}px, 100vw);
120
+ border-right: 1px solid var(--scalar-border-color);
121
+ }
122
+
123
+ .scalar-card,
124
+ .t-doc__sidebar,
125
+ .references-layout .reference-layout__content .request-card,
126
+ .references-layout .reference-layout__content .response-card,
127
+ .references-layout .reference-layout__content .scalar-card-header,
128
+ .references-layout .reference-layout__content .scalar-card-footer,
129
+ .references-layout .reference-layout__content .section,
130
+ .references-layout .reference-layout__content .section-container {
131
+ border-color: var(--scalar-border-color) !important;
132
+ }
133
+
134
+ .t-doc__sidebar,
135
+ .t-doc__sidebar * {
136
+ font-family: var(--scalar-font);
137
+ }
138
+
139
+ .t-doc__sidebar .sidebar-search {
140
+ margin: 0.5rem 0 1rem;
141
+ }
142
+
143
+ .t-doc__sidebar .sidebar-search input {
144
+ border-radius: 14px;
145
+ }
146
+
147
+ .t-doc__sidebar .sidebar-item,
148
+ .t-doc__sidebar .sidebar-heading {
149
+ border-radius: 14px;
150
+ }
151
+
152
+ .t-doc__sidebar .sidebar-group-label {
153
+ font-size: 0.72rem;
154
+ letter-spacing: 0.08em;
155
+ text-transform: uppercase;
156
+ color: var(--scalar-color-3);
157
+ }
158
+
159
+ .t-doc__sidebar .sidebar-item--active {
160
+ font-weight: 600;
161
+ }
162
+
163
+ .scalar-card,
164
+ .references-layout .reference-layout__content .request-card,
165
+ .references-layout .reference-layout__content .response-card {
166
+ border-radius: 18px;
167
+ }
168
+
169
+ .references-layout .reference-layout__content {
170
+ padding-top: 1.5rem;
171
+ }
172
+
173
+ .references-layout .section-content,
174
+ .references-layout .section-flare {
175
+ background: transparent;
176
+ }
177
+
178
+ .references-layout .reference-layout__content,
179
+ .references-layout .reference-layout__content * {
180
+ font-family: var(--scalar-font);
181
+ }
182
+
183
+ .references-layout code,
184
+ .references-layout pre,
185
+ .references-layout .scalar-codeblock {
186
+ font-family: var(--scalar-font-code);
187
+ }
188
+ `;
189
+ }
190
+ export function buildApiReferenceOpenApiDocument(config, options) {
191
+ const routes = buildApiReferenceRoutes(config, options);
192
+ const tags = Array.from(new Set(routes.map((route) => route.tag))).map((name) => ({
193
+ name,
194
+ description: `${name} endpoints`,
195
+ }));
196
+ return {
197
+ openapi: "3.1.0",
198
+ info: {
199
+ title: "API Reference",
200
+ description: config.metadata?.description ?? `Generated API reference for ${options.framework}.`,
201
+ version: "0.0.0",
202
+ },
203
+ servers: [{ url: "/" }],
204
+ tags,
205
+ paths: buildOpenApiPaths(routes),
206
+ };
207
+ }
208
+ export function buildApiReferenceHtmlDocument(config, options) {
209
+ const apiReference = resolveApiReferenceConfig(config.apiReference);
210
+ const rootDir = options.rootDir ?? process.cwd();
211
+ const title = options.title ?? "API Reference";
212
+ return getHtmlDocument({
213
+ pageTitle: buildApiReferencePageTitle(config, title),
214
+ title,
215
+ content: () => buildApiReferenceOpenApiDocument(config, {
216
+ framework: options.framework,
217
+ rootDir,
218
+ }),
219
+ theme: "deepSpace",
220
+ layout: "modern",
221
+ customCss: buildApiReferenceScalarCss(config),
222
+ pathRouting: {
223
+ basePath: `/${apiReference.path}`,
224
+ },
225
+ showSidebar: true,
226
+ defaultOpenFirstTag: true,
227
+ tagsSorter: "alpha",
228
+ operationsSorter: "alpha",
229
+ operationTitleSource: "summary",
230
+ defaultHttpClient: {
231
+ targetKey: "shell",
232
+ clientKey: "curl",
233
+ },
234
+ documentDownloadType: "json",
235
+ });
236
+ }
237
+ function buildApiReferenceRoutes(config, options) {
238
+ const apiReference = resolveApiReferenceConfig(config.apiReference);
239
+ if (!apiReference.enabled)
240
+ return [];
241
+ const rootDir = options.rootDir ?? process.cwd();
242
+ switch (options.framework) {
243
+ case "next":
244
+ return buildFileConventionRoutes({
245
+ rootDir,
246
+ sourceDir: resolveRootedDir(rootDir, apiReference.routeRoot, getNextAppDir(rootDir)),
247
+ routePathBase: toRouteBase(apiReference.routeRoot, getNextAppDir(rootDir)),
248
+ isRouteFile: (name) => NEXT_ROUTE_FILE_RE.test(name),
249
+ toRouteSegments: (relativeFile) => relativeFile.split("/").slice(0, -1).filter(Boolean),
250
+ config,
251
+ exclude: apiReference.exclude,
252
+ });
253
+ case "sveltekit":
254
+ return buildFileConventionRoutes({
255
+ rootDir,
256
+ sourceDir: resolveRootedDir(rootDir, apiReference.routeRoot, "src/routes"),
257
+ routePathBase: toRouteBase(apiReference.routeRoot, "src/routes"),
258
+ isRouteFile: (name) => SVELTE_ROUTE_FILE_RE.test(name),
259
+ toRouteSegments: (relativeFile) => relativeFile.split("/").slice(0, -1).filter(Boolean),
260
+ config,
261
+ exclude: apiReference.exclude,
262
+ });
263
+ case "astro":
264
+ return buildFileConventionRoutes({
265
+ rootDir,
266
+ sourceDir: resolveRootedDir(rootDir, apiReference.routeRoot, "src/pages"),
267
+ routePathBase: toRouteBase(apiReference.routeRoot, "src/pages"),
268
+ isRouteFile: (name) => ASTRO_ROUTE_FILE_RE.test(name),
269
+ toRouteSegments: (relativeFile) => routeSegmentsFromEndpointFile(relativeFile),
270
+ config,
271
+ exclude: apiReference.exclude,
272
+ });
273
+ case "nuxt":
274
+ return buildFileConventionRoutes({
275
+ rootDir,
276
+ sourceDir: resolveRootedDir(rootDir, apiReference.routeRoot, "server"),
277
+ routePathBase: toRouteBase(apiReference.routeRoot, "server"),
278
+ isRouteFile: (name) => NUXT_ROUTE_FILE_RE.test(name),
279
+ toRouteSegments: (relativeFile) => routeSegmentsFromEndpointFile(stripNuxtMethodSuffix(relativeFile)),
280
+ config,
281
+ exclude: apiReference.exclude,
282
+ getMethods: (source, file) => extractNuxtMethods(source, file),
283
+ });
284
+ case "tanstack-start":
285
+ return buildTanstackRoutes(config, rootDir, apiReference);
286
+ }
287
+ }
288
+ function buildFileConventionRoutes({ rootDir, sourceDir, routePathBase, isRouteFile, toRouteSegments, config, exclude, getMethods = extractMethods, }) {
289
+ const files = scanRouteFiles(sourceDir, isRouteFile);
290
+ const routes = [];
291
+ for (const file of files) {
292
+ const source = readFileSync(file, "utf-8");
293
+ const methods = getMethods(source, file);
294
+ if (methods.length === 0)
295
+ continue;
296
+ const relativeFile = relative(sourceDir, file).replace(/\\/g, "/");
297
+ const routeSegments = toRouteSegments(relativeFile);
298
+ const routePath = buildRoutePath(routePathBase, routeSegments);
299
+ if (shouldExcludeRoute(exclude, routePath, relativeFile, routeSegments.join("/")))
300
+ continue;
301
+ routes.push(createApiReferenceRoute({
302
+ rootDir,
303
+ file,
304
+ source,
305
+ methods,
306
+ routePath,
307
+ }));
308
+ }
309
+ return routes.sort((a, b) => a.routePath.localeCompare(b.routePath));
310
+ }
311
+ function buildTanstackRoutes(config, rootDir, apiReference) {
312
+ const routesDir = join(rootDir, "src", "routes");
313
+ const files = scanRouteFiles(routesDir, (name) => TANSTACK_ROUTE_FILE_RE.test(name));
314
+ const routeBase = `/${normalizePathSegment(apiReference.routeRoot)}`;
315
+ const routes = [];
316
+ for (const file of files) {
317
+ const source = readFileSync(file, "utf-8");
318
+ if (!source.includes("createFileRoute(") || !source.includes("handlers"))
319
+ continue;
320
+ const pathMatch = source.match(/createFileRoute\(\s*["'`]([^"'`]+)["'`]\s*\)/);
321
+ if (!pathMatch)
322
+ continue;
323
+ const routePath = normalizeTanstackRoutePath(pathMatch[1]);
324
+ if (!routePath.startsWith(routeBase))
325
+ continue;
326
+ const methods = extractTanstackMethods(source);
327
+ if (methods.length === 0)
328
+ continue;
329
+ const relativeFile = relative(routesDir, file).replace(/\\/g, "/");
330
+ if (shouldExcludeRoute(apiReference.exclude, routePath, relativeFile, relativeFile))
331
+ continue;
332
+ routes.push(createApiReferenceRoute({
333
+ rootDir,
334
+ file,
335
+ source,
336
+ methods,
337
+ routePath,
338
+ }));
339
+ }
340
+ return routes.sort((a, b) => a.routePath.localeCompare(b.routePath));
341
+ }
342
+ function createApiReferenceRoute({ rootDir, file, source, methods, routePath, }) {
343
+ const docBlock = extractDocBlock(source);
344
+ const pathSegments = routePath.split("/").filter(Boolean);
345
+ const titleSegment = pathSegments[pathSegments.length - 1] ?? "overview";
346
+ const tagSegment = pathSegments[0] ?? "general";
347
+ const title = humanizeSegment(titleSegment);
348
+ return {
349
+ title,
350
+ summary: docBlock.summary ?? `${title} endpoint`,
351
+ description: docBlock.description,
352
+ routePath,
353
+ sourceFile: relative(rootDir, file).replace(/\\/g, "/"),
354
+ methods,
355
+ tag: humanizeSegment(tagSegment),
356
+ parameters: buildPathParameters(routePath),
357
+ };
358
+ }
359
+ function buildPathParameters(routePath) {
360
+ const parameters = [];
361
+ for (const segment of routePath.split("/")) {
362
+ const match = segment.match(/^\{(.+)\}$/);
363
+ if (!match)
364
+ continue;
365
+ parameters.push({
366
+ name: match[1],
367
+ in: "path",
368
+ required: true,
369
+ description: `${humanizeSegment(match[1])} path parameter.`,
370
+ schema: {
371
+ type: "string",
372
+ },
373
+ });
374
+ }
375
+ return parameters;
376
+ }
377
+ function buildOpenApiPaths(routes) {
378
+ const paths = {};
379
+ for (const route of routes) {
380
+ const pathItem = {};
381
+ for (const method of route.methods) {
382
+ pathItem[method.toLowerCase()] = {
383
+ tags: [route.tag],
384
+ summary: route.summary,
385
+ description: route.description ?? route.summary,
386
+ operationId: createOperationId(route, method),
387
+ ...(route.parameters.length > 0 ? { parameters: route.parameters } : {}),
388
+ ...(buildRequestBody(method) ? { requestBody: buildRequestBody(method) } : {}),
389
+ responses: buildResponses(method),
390
+ "x-farming-labs-source": route.sourceFile,
391
+ };
392
+ }
393
+ paths[route.routePath] = pathItem;
394
+ }
395
+ return paths;
396
+ }
397
+ function buildRequestBody(method) {
398
+ if (!["POST", "PUT", "PATCH"].includes(method))
399
+ return undefined;
400
+ return {
401
+ required: method === "POST",
402
+ content: {
403
+ "application/json": {
404
+ schema: {
405
+ type: "object",
406
+ additionalProperties: true,
407
+ },
408
+ example: {
409
+ example: true,
410
+ },
411
+ },
412
+ },
413
+ };
414
+ }
415
+ function buildResponses(method) {
416
+ return {
417
+ "200": {
418
+ description: method === "DELETE" ? "Resource removed successfully." : "Request completed successfully.",
419
+ content: {
420
+ "application/json": {
421
+ schema: {
422
+ type: "object",
423
+ additionalProperties: true,
424
+ },
425
+ example: {
426
+ ok: true,
427
+ },
428
+ },
429
+ },
430
+ },
431
+ };
432
+ }
433
+ function createOperationId(route, method) {
434
+ return `${method.toLowerCase()}_${route.routePath.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "")}`;
435
+ }
436
+ function resolveTheme(config) {
437
+ return config.theme;
438
+ }
439
+ function normalizeApiReferenceExcludes(values) {
440
+ return (values ?? []).map(normalizeExcludeMatcher).filter(Boolean);
441
+ }
442
+ function normalizeExcludeMatcher(value) {
443
+ return value
444
+ .replace(/\\/g, "/")
445
+ .replace(/^\/+|\/+$/g, "")
446
+ .replace(/\.(ts|tsx|js|jsx|mjs|mts)$/i, "")
447
+ .replace(/\/route$/i, "")
448
+ .replace(/\/\+server$/i, "")
449
+ .replace(/\/index$/i, "")
450
+ .replace(/\.(get|post|put|patch|delete|options|head)$/i, "");
451
+ }
452
+ function shouldExcludeRoute(excludes, routePath, relativeFile, relativeDir) {
453
+ if (excludes.length === 0)
454
+ return false;
455
+ const candidates = new Set([
456
+ normalizeExcludeMatcher(routePath),
457
+ normalizeExcludeMatcher(routePath.replace(/^\/+/, "")),
458
+ normalizeExcludeMatcher(relativeFile),
459
+ normalizeExcludeMatcher(relativeDir),
460
+ ]);
461
+ return excludes.some((entry) => candidates.has(entry));
462
+ }
463
+ function scanRouteFiles(dir, isRouteFile) {
464
+ if (!existsSync(dir))
465
+ return [];
466
+ const results = [];
467
+ for (const name of readdirSync(dir)) {
468
+ const full = join(dir, name);
469
+ const stats = statSync(full);
470
+ if (stats.isDirectory()) {
471
+ results.push(...scanRouteFiles(full, isRouteFile));
472
+ continue;
473
+ }
474
+ if (isRouteFile(name))
475
+ results.push(full);
476
+ }
477
+ return results;
478
+ }
479
+ function resolveRootedDir(rootDir, routeRoot, defaultRoot) {
480
+ const normalized = normalizePathSegment(routeRoot) || "api";
481
+ if (normalized === defaultRoot || normalized.startsWith(`${defaultRoot}/`)) {
482
+ return join(rootDir, ...normalized.split("/"));
483
+ }
484
+ return join(rootDir, ...defaultRoot.split("/"), ...normalized.split("/"));
485
+ }
486
+ function toRouteBase(routeRoot, defaultRoot) {
487
+ const normalized = normalizePathSegment(routeRoot) || "api";
488
+ const base = normalized === defaultRoot || normalized.startsWith(`${defaultRoot}/`)
489
+ ? normalized.slice(defaultRoot.length).replace(/^\/+/, "")
490
+ : normalized;
491
+ return `/${normalizePathSegment(base)}`;
492
+ }
493
+ function getNextAppDir(rootDir) {
494
+ if (existsSync(join(rootDir, "src", "app")))
495
+ return "src/app";
496
+ return "app";
497
+ }
498
+ function routeSegmentsFromEndpointFile(relativeFile) {
499
+ const segments = relativeFile.split("/");
500
+ const last = segments.pop() ?? "";
501
+ const name = last.replace(/\.(ts|js|mts|mjs)$/i, "");
502
+ if (name !== "index")
503
+ segments.push(name);
504
+ return segments.filter(Boolean);
505
+ }
506
+ function stripNuxtMethodSuffix(relativeFile) {
507
+ return relativeFile.replace(/\.(get|post|put|patch|delete|options|head)(?=\.(ts|js|mts|mjs)$)/i, "");
508
+ }
509
+ function buildRoutePath(basePath, rawSegments) {
510
+ const segments = rawSegments
511
+ .filter(Boolean)
512
+ .map((segment) => endpointSegmentFromConvention(segment))
513
+ .join("/");
514
+ const normalizedBase = normalizePathSegment(basePath);
515
+ const path = [normalizedBase, segments].filter(Boolean).join("/");
516
+ return path ? `/${path}` : "/";
517
+ }
518
+ function endpointSegmentFromConvention(value) {
519
+ if (value.startsWith("[[...") && value.endsWith("]]"))
520
+ return `{${value.slice(5, -2)}}`;
521
+ if (value.startsWith("[...") && value.endsWith("]"))
522
+ return `{${value.slice(4, -1)}}`;
523
+ if (value.startsWith("[") && value.endsWith("]"))
524
+ return `{${value.slice(1, -1)}}`;
525
+ return value;
526
+ }
527
+ function normalizeTanstackRoutePath(value) {
528
+ return `/${value
529
+ .replace(/^\/+|\/+$/g, "")
530
+ .split("/")
531
+ .map((segment) => (segment.startsWith("$") ? `{${segment.slice(1)}}` : segment))
532
+ .filter(Boolean)
533
+ .join("/")}`;
534
+ }
535
+ function extractDocBlock(source) {
536
+ const match = source.match(/\/\*\*([\s\S]*?)\*\//);
537
+ if (!match)
538
+ return {};
539
+ const lines = match[1]
540
+ .split("\n")
541
+ .map((line) => line.replace(/^\s*\*\s?/, "").trim())
542
+ .filter(Boolean)
543
+ .filter((line) => !line.startsWith("@"));
544
+ if (lines.length === 0)
545
+ return {};
546
+ return {
547
+ summary: lines[0],
548
+ description: lines.slice(1).join(" "),
549
+ };
550
+ }
551
+ function extractMethods(source) {
552
+ const methods = new Set();
553
+ for (const match of source.matchAll(METHOD_RE)) {
554
+ if (match[1] === "ALL") {
555
+ METHOD_NAMES.forEach((method) => methods.add(method));
556
+ continue;
557
+ }
558
+ methods.add(match[1]);
559
+ }
560
+ return Array.from(methods);
561
+ }
562
+ function extractNuxtMethods(source, file) {
563
+ const methods = extractMethods(source);
564
+ if (methods.length > 0)
565
+ return methods;
566
+ const suffix = basename(file).match(/\.(get|post|put|patch|delete|options|head)\.(ts|js|mts|mjs)$/i);
567
+ if (suffix)
568
+ return [suffix[1].toUpperCase()];
569
+ if (/defineEventHandler|eventHandler/.test(source))
570
+ return ["GET"];
571
+ return [];
572
+ }
573
+ function extractTanstackMethods(source) {
574
+ const methods = new Set();
575
+ const handlersMatch = source.match(/handlers\s*:\s*\{([\s\S]*?)\}/m);
576
+ if (!handlersMatch)
577
+ return [];
578
+ for (const match of handlersMatch[1].matchAll(/\b(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\s*:/g)) {
579
+ methods.add(match[1]);
580
+ }
581
+ return Array.from(methods);
582
+ }
583
+ function humanizeSegment(value) {
584
+ const normalized = value
585
+ .replace(/^\{/, "")
586
+ .replace(/\}$/, "")
587
+ .replace(/^\[\[?\.{3}/, "")
588
+ .replace(/^\[/, "")
589
+ .replace(/\]\]?$/, "")
590
+ .replace(/^\$/, "")
591
+ .replace(/-/g, " ");
592
+ return normalized.replace(/\b\w/g, (char) => char.toUpperCase());
593
+ }
594
+ //# sourceMappingURL=api-reference.js.map