@specglass/core 0.0.2

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 (95) hide show
  1. package/dist/config/defaults.d.ts +4 -0
  2. package/dist/config/defaults.d.ts.map +1 -0
  3. package/dist/config/defaults.js +31 -0
  4. package/dist/config/defaults.js.map +1 -0
  5. package/dist/config/define-config.d.ts +17 -0
  6. package/dist/config/define-config.d.ts.map +1 -0
  7. package/dist/config/define-config.js +55 -0
  8. package/dist/config/define-config.js.map +1 -0
  9. package/dist/config/loader.d.ts +11 -0
  10. package/dist/config/loader.d.ts.map +1 -0
  11. package/dist/config/loader.js +74 -0
  12. package/dist/config/loader.js.map +1 -0
  13. package/dist/config/schema.d.ts +366 -0
  14. package/dist/config/schema.d.ts.map +1 -0
  15. package/dist/config/schema.js +109 -0
  16. package/dist/config/schema.js.map +1 -0
  17. package/dist/content/frontmatter-schema.d.ts +53 -0
  18. package/dist/content/frontmatter-schema.d.ts.map +1 -0
  19. package/dist/content/frontmatter-schema.js +27 -0
  20. package/dist/content/frontmatter-schema.js.map +1 -0
  21. package/dist/content/mdx-loader.d.ts +93 -0
  22. package/dist/content/mdx-loader.d.ts.map +1 -0
  23. package/dist/content/mdx-loader.js +97 -0
  24. package/dist/content/mdx-loader.js.map +1 -0
  25. package/dist/content/openapi-loader.d.ts +40 -0
  26. package/dist/content/openapi-loader.d.ts.map +1 -0
  27. package/dist/content/openapi-loader.js +58 -0
  28. package/dist/content/openapi-loader.js.map +1 -0
  29. package/dist/content/rehype-code-blocks.d.ts +15 -0
  30. package/dist/content/rehype-code-blocks.d.ts.map +1 -0
  31. package/dist/content/rehype-code-blocks.js +84 -0
  32. package/dist/content/rehype-code-blocks.js.map +1 -0
  33. package/dist/errors/specglass-error.d.ts +12 -0
  34. package/dist/errors/specglass-error.d.ts.map +1 -0
  35. package/dist/errors/specglass-error.js +19 -0
  36. package/dist/errors/specglass-error.js.map +1 -0
  37. package/dist/index.d.ts +26 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +26 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/integration.d.ts +41 -0
  42. package/dist/integration.d.ts.map +1 -0
  43. package/dist/integration.js +276 -0
  44. package/dist/integration.js.map +1 -0
  45. package/dist/navigation/builder.d.ts +24 -0
  46. package/dist/navigation/builder.d.ts.map +1 -0
  47. package/dist/navigation/builder.js +169 -0
  48. package/dist/navigation/builder.js.map +1 -0
  49. package/dist/navigation/index.d.ts +7 -0
  50. package/dist/navigation/index.d.ts.map +1 -0
  51. package/dist/navigation/index.js +6 -0
  52. package/dist/navigation/index.js.map +1 -0
  53. package/dist/navigation/meta-parser.d.ts +9 -0
  54. package/dist/navigation/meta-parser.d.ts.map +1 -0
  55. package/dist/navigation/meta-parser.js +59 -0
  56. package/dist/navigation/meta-parser.js.map +1 -0
  57. package/dist/navigation/meta-schema.d.ts +77 -0
  58. package/dist/navigation/meta-schema.d.ts.map +1 -0
  59. package/dist/navigation/meta-schema.js +31 -0
  60. package/dist/navigation/meta-schema.js.map +1 -0
  61. package/dist/navigation/watcher.d.ts +44 -0
  62. package/dist/navigation/watcher.d.ts.map +1 -0
  63. package/dist/navigation/watcher.js +81 -0
  64. package/dist/navigation/watcher.js.map +1 -0
  65. package/dist/openapi/parser.d.ts +24 -0
  66. package/dist/openapi/parser.d.ts.map +1 -0
  67. package/dist/openapi/parser.js +53 -0
  68. package/dist/openapi/parser.js.map +1 -0
  69. package/dist/openapi/transformer.d.ts +19 -0
  70. package/dist/openapi/transformer.d.ts.map +1 -0
  71. package/dist/openapi/transformer.js +294 -0
  72. package/dist/openapi/transformer.js.map +1 -0
  73. package/dist/openapi/types.d.ts +109 -0
  74. package/dist/openapi/types.d.ts.map +1 -0
  75. package/dist/openapi/types.js +11 -0
  76. package/dist/openapi/types.js.map +1 -0
  77. package/dist/openapi/utils.d.ts +26 -0
  78. package/dist/openapi/utils.d.ts.map +1 -0
  79. package/dist/openapi/utils.js +34 -0
  80. package/dist/openapi/utils.js.map +1 -0
  81. package/dist/types/config.d.ts +7 -0
  82. package/dist/types/config.d.ts.map +1 -0
  83. package/dist/types/config.js +2 -0
  84. package/dist/types/config.js.map +1 -0
  85. package/dist/types/navigation.d.ts +62 -0
  86. package/dist/types/navigation.d.ts.map +1 -0
  87. package/dist/types/navigation.js +2 -0
  88. package/dist/types/navigation.js.map +1 -0
  89. package/dist/virtual/modules.d.ts +34 -0
  90. package/dist/virtual/modules.d.ts.map +1 -0
  91. package/dist/virtual/modules.js +37 -0
  92. package/dist/virtual/modules.js.map +1 -0
  93. package/package.json +51 -0
  94. package/src/pages/[...slug].astro +55 -0
  95. package/src/pages/api-reference/[...slug].astro +67 -0
@@ -0,0 +1,6 @@
1
+ // Navigation — public API
2
+ export { buildNavigationTree, toTitleCase } from "./builder.js";
3
+ export { parseMetaJson } from "./meta-parser.js";
4
+ export { metaJsonSchema, metaJsonEntryValueSchema, metaJsonEntryObjectSchema, } from "./meta-schema.js";
5
+ export { createNavigationWatcher, isNavigationRelevant, } from "./watcher.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/navigation/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { MetaJsonEntry } from "../types/navigation.js";
2
+ /**
3
+ * Parse a `_meta.json` file from the given directory.
4
+ *
5
+ * @param dirPath - Absolute path to the directory containing `_meta.json`
6
+ * @returns Ordered array of `MetaJsonEntry`, or `null` if file is missing or invalid
7
+ */
8
+ export declare function parseMetaJson(dirPath: string): Promise<MetaJsonEntry[] | null>;
9
+ //# sourceMappingURL=meta-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-parser.d.ts","sourceRoot":"","sources":["../../src/navigation/meta-parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,wBAAwB,CAAC;AAqBhF;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAqCjC"}
@@ -0,0 +1,59 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { metaJsonSchema } from "./meta-schema.js";
4
+ /**
5
+ * Normalize a raw `_meta.json` entry value into a `MetaJsonEntry`.
6
+ *
7
+ * String values are shorthand for `{ title: "value" }`.
8
+ */
9
+ function normalizeEntry(key, value) {
10
+ if (typeof value === "string") {
11
+ return { key, title: value };
12
+ }
13
+ return {
14
+ key,
15
+ title: value.title,
16
+ ...(value.collapsed !== undefined && { collapsed: value.collapsed }),
17
+ ...(value.icon !== undefined && { icon: value.icon }),
18
+ ...(value.href !== undefined && { href: value.href }),
19
+ ...(value.hidden !== undefined && { hidden: value.hidden }),
20
+ };
21
+ }
22
+ /**
23
+ * Parse a `_meta.json` file from the given directory.
24
+ *
25
+ * @param dirPath - Absolute path to the directory containing `_meta.json`
26
+ * @returns Ordered array of `MetaJsonEntry`, or `null` if file is missing or invalid
27
+ */
28
+ export async function parseMetaJson(dirPath) {
29
+ const filePath = join(dirPath, "_meta.json");
30
+ let raw;
31
+ try {
32
+ raw = await readFile(filePath, "utf-8");
33
+ }
34
+ catch {
35
+ // File doesn't exist — not an error, just no meta
36
+ return null;
37
+ }
38
+ // Empty file → empty array (valid but no entries)
39
+ const trimmed = raw.trim();
40
+ if (trimmed === "") {
41
+ return [];
42
+ }
43
+ let parsed;
44
+ try {
45
+ parsed = JSON.parse(trimmed);
46
+ }
47
+ catch {
48
+ console.warn(`[specglass] Invalid JSON in ${filePath} — falling back to alphabetical order`);
49
+ return null;
50
+ }
51
+ const result = metaJsonSchema.safeParse(parsed);
52
+ if (!result.success) {
53
+ console.warn(`[specglass] Invalid _meta.json schema in ${filePath} — falling back to alphabetical order`);
54
+ return null;
55
+ }
56
+ // Preserve JSON key order (Object.entries preserves insertion order)
57
+ return Object.entries(result.data).map(([key, value]) => normalizeEntry(key, value));
58
+ }
59
+ //# sourceMappingURL=meta-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-parser.js","sourceRoot":"","sources":["../../src/navigation/meta-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;;GAIG;AACH,SAAS,cAAc,CAAC,GAAW,EAAE,KAAyB;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO;QACL,GAAG;QACH,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;QACpE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QACrD,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QACrD,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe;IAEf,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE7C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kDAAkD;IAClD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,+BAA+B,QAAQ,uCAAuC,CAAC,CAAC;QAC7F,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CACV,4CAA4C,QAAQ,uCAAuC,CAC5F,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qEAAqE;IACrE,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CACtD,cAAc,CAAC,GAAG,EAAE,KAA2B,CAAC,CACjD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Zod schema for the object form of a `_meta.json` entry value.
4
+ *
5
+ * Supports: `title` (required), `collapsed`, `icon`, `href`, `hidden`.
6
+ */
7
+ export declare const metaJsonEntryObjectSchema: z.ZodObject<{
8
+ title: z.ZodString;
9
+ collapsed: z.ZodOptional<z.ZodBoolean>;
10
+ icon: z.ZodOptional<z.ZodString>;
11
+ href: z.ZodOptional<z.ZodString>;
12
+ hidden: z.ZodOptional<z.ZodBoolean>;
13
+ }, "strip", z.ZodTypeAny, {
14
+ title: string;
15
+ href?: string | undefined;
16
+ collapsed?: boolean | undefined;
17
+ icon?: string | undefined;
18
+ hidden?: boolean | undefined;
19
+ }, {
20
+ title: string;
21
+ href?: string | undefined;
22
+ collapsed?: boolean | undefined;
23
+ icon?: string | undefined;
24
+ hidden?: boolean | undefined;
25
+ }>;
26
+ /**
27
+ * Zod schema for a single `_meta.json` entry value.
28
+ *
29
+ * - String values are shorthand for `{ title: "value" }`
30
+ * - Object values provide extended configuration
31
+ */
32
+ export declare const metaJsonEntryValueSchema: z.ZodUnion<[z.ZodString, z.ZodObject<{
33
+ title: z.ZodString;
34
+ collapsed: z.ZodOptional<z.ZodBoolean>;
35
+ icon: z.ZodOptional<z.ZodString>;
36
+ href: z.ZodOptional<z.ZodString>;
37
+ hidden: z.ZodOptional<z.ZodBoolean>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ title: string;
40
+ href?: string | undefined;
41
+ collapsed?: boolean | undefined;
42
+ icon?: string | undefined;
43
+ hidden?: boolean | undefined;
44
+ }, {
45
+ title: string;
46
+ href?: string | undefined;
47
+ collapsed?: boolean | undefined;
48
+ icon?: string | undefined;
49
+ hidden?: boolean | undefined;
50
+ }>]>;
51
+ /**
52
+ * Zod schema for a complete `_meta.json` file.
53
+ *
54
+ * The file is a flat key-value object where keys are filenames
55
+ * (without extension) and values are either strings or config objects.
56
+ */
57
+ export declare const metaJsonSchema: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodObject<{
58
+ title: z.ZodString;
59
+ collapsed: z.ZodOptional<z.ZodBoolean>;
60
+ icon: z.ZodOptional<z.ZodString>;
61
+ href: z.ZodOptional<z.ZodString>;
62
+ hidden: z.ZodOptional<z.ZodBoolean>;
63
+ }, "strip", z.ZodTypeAny, {
64
+ title: string;
65
+ href?: string | undefined;
66
+ collapsed?: boolean | undefined;
67
+ icon?: string | undefined;
68
+ hidden?: boolean | undefined;
69
+ }, {
70
+ title: string;
71
+ href?: string | undefined;
72
+ collapsed?: boolean | undefined;
73
+ icon?: string | undefined;
74
+ hidden?: boolean | undefined;
75
+ }>]>>;
76
+ export type MetaJsonSchemaInput = z.input<typeof metaJsonSchema>;
77
+ //# sourceMappingURL=meta-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-schema.d.ts","sourceRoot":"","sources":["../../src/navigation/meta-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;EAMpC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;IAGnC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;KAAiD,CAAC;AAE7E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Zod schema for the object form of a `_meta.json` entry value.
4
+ *
5
+ * Supports: `title` (required), `collapsed`, `icon`, `href`, `hidden`.
6
+ */
7
+ export const metaJsonEntryObjectSchema = z.object({
8
+ title: z.string(),
9
+ collapsed: z.boolean().optional(),
10
+ icon: z.string().optional(),
11
+ href: z.string().optional(),
12
+ hidden: z.boolean().optional(),
13
+ });
14
+ /**
15
+ * Zod schema for a single `_meta.json` entry value.
16
+ *
17
+ * - String values are shorthand for `{ title: "value" }`
18
+ * - Object values provide extended configuration
19
+ */
20
+ export const metaJsonEntryValueSchema = z.union([
21
+ z.string(),
22
+ metaJsonEntryObjectSchema,
23
+ ]);
24
+ /**
25
+ * Zod schema for a complete `_meta.json` file.
26
+ *
27
+ * The file is a flat key-value object where keys are filenames
28
+ * (without extension) and values are either strings or config objects.
29
+ */
30
+ export const metaJsonSchema = z.record(z.string(), metaJsonEntryValueSchema);
31
+ //# sourceMappingURL=meta-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-schema.js","sourceRoot":"","sources":["../../src/navigation/meta-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC;IAC9C,CAAC,CAAC,MAAM,EAAE;IACV,yBAAyB;CAC1B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { NavigationTree } from "../types/navigation.js";
2
+ /**
3
+ * Options for creating a navigation file watcher.
4
+ */
5
+ export interface NavigationWatcherOptions {
6
+ /** Absolute path to the content directory to watch. */
7
+ contentDir: string;
8
+ /** Callback invoked with the new navigation tree when relevant files change. */
9
+ onNavigationUpdate: (tree: NavigationTree) => void;
10
+ /** Debounce window in milliseconds. Defaults to 100. */
11
+ debounceMs?: number;
12
+ }
13
+ /**
14
+ * Check whether a file change should trigger a navigation rebuild.
15
+ *
16
+ * Navigation-relevant changes are:
17
+ * - Addition or removal of `.mdx` / `.md` files
18
+ * - Modification of `_meta.json` files
19
+ *
20
+ * @param filePath - Absolute path of the changed file
21
+ * @param contentDir - Absolute path of the watched content directory
22
+ * @returns `true` if the change should trigger a navigation rebuild
23
+ */
24
+ export declare function isNavigationRelevant(filePath: string, contentDir: string): boolean;
25
+ /**
26
+ * Create a navigation watcher that rebuilds the navigation tree
27
+ * when relevant content files change.
28
+ *
29
+ * The watcher debounces rapid file system events (e.g., git checkout)
30
+ * to avoid redundant rebuilds.
31
+ *
32
+ * @param options - Configuration for the watcher
33
+ * @returns A cleanup function that stops the watcher's debounce timer
34
+ */
35
+ export declare function createNavigationWatcher(options: NavigationWatcherOptions): {
36
+ /**
37
+ * Call this when a file system event occurs.
38
+ * The watcher will check relevance and debounce before triggering a rebuild.
39
+ */
40
+ handleFileChange: (filePath: string) => void;
41
+ /** Stop any pending debounced rebuild. */
42
+ cleanup: () => void;
43
+ };
44
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/navigation/watcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG7D;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,kBAAkB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACnD,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAmBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG;IAC1E;;;OAGG;IACH,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,0CAA0C;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAkCA"}
@@ -0,0 +1,81 @@
1
+ import { basename, extname } from "node:path";
2
+ import { buildNavigationTree } from "./builder.js";
3
+ /**
4
+ * File extensions that are considered navigation-relevant content files.
5
+ */
6
+ const CONTENT_EXTENSIONS = new Set([".mdx", ".md"]);
7
+ /**
8
+ * Filename that controls navigation ordering and metadata.
9
+ */
10
+ const META_FILE = "_meta.json";
11
+ /**
12
+ * Check whether a file change should trigger a navigation rebuild.
13
+ *
14
+ * Navigation-relevant changes are:
15
+ * - Addition or removal of `.mdx` / `.md` files
16
+ * - Modification of `_meta.json` files
17
+ *
18
+ * @param filePath - Absolute path of the changed file
19
+ * @param contentDir - Absolute path of the watched content directory
20
+ * @returns `true` if the change should trigger a navigation rebuild
21
+ */
22
+ export function isNavigationRelevant(filePath, contentDir) {
23
+ // Must be within the content directory (ensure trailing slash to prevent
24
+ // sibling directory matches, e.g., docs-backup/ matching docs/)
25
+ const normalizedDir = contentDir.endsWith("/")
26
+ ? contentDir
27
+ : contentDir + "/";
28
+ if (!filePath.startsWith(normalizedDir)) {
29
+ return false;
30
+ }
31
+ const name = basename(filePath);
32
+ // _meta.json changes always affect navigation
33
+ if (name === META_FILE) {
34
+ return true;
35
+ }
36
+ // Content file additions/removals affect navigation
37
+ return CONTENT_EXTENSIONS.has(extname(name));
38
+ }
39
+ /**
40
+ * Create a navigation watcher that rebuilds the navigation tree
41
+ * when relevant content files change.
42
+ *
43
+ * The watcher debounces rapid file system events (e.g., git checkout)
44
+ * to avoid redundant rebuilds.
45
+ *
46
+ * @param options - Configuration for the watcher
47
+ * @returns A cleanup function that stops the watcher's debounce timer
48
+ */
49
+ export function createNavigationWatcher(options) {
50
+ const { contentDir, onNavigationUpdate, debounceMs = 100 } = options;
51
+ let debounceTimer = null;
52
+ function scheduleRebuild() {
53
+ if (debounceTimer !== null) {
54
+ clearTimeout(debounceTimer);
55
+ }
56
+ debounceTimer = setTimeout(async () => {
57
+ debounceTimer = null;
58
+ try {
59
+ const tree = await buildNavigationTree(contentDir);
60
+ onNavigationUpdate(tree);
61
+ }
62
+ catch {
63
+ // If the build fails (e.g., directory temporarily missing during git operations),
64
+ // silently ignore — the next change will trigger another rebuild.
65
+ }
66
+ }, debounceMs);
67
+ }
68
+ function handleFileChange(filePath) {
69
+ if (isNavigationRelevant(filePath, contentDir)) {
70
+ scheduleRebuild();
71
+ }
72
+ }
73
+ function cleanup() {
74
+ if (debounceTimer !== null) {
75
+ clearTimeout(debounceTimer);
76
+ debounceTimer = null;
77
+ }
78
+ }
79
+ return { handleFileChange, cleanup };
80
+ }
81
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/navigation/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAcnD;;GAEG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAEpD;;GAEG;AACH,MAAM,SAAS,GAAG,YAAY,CAAC;AAE/B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,UAAkB;IAElB,yEAAyE;IACzE,gEAAgE;IAChE,MAAM,aAAa,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC5C,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC;IACrB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEhC,8CAA8C;IAC9C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oDAAoD;IACpD,OAAO,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAiC;IASvE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,UAAU,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IACrE,IAAI,aAAa,GAAyC,IAAI,CAAC;IAE/D,SAAS,eAAe;QACtB,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,YAAY,CAAC,aAAa,CAAC,CAAC;QAC9B,CAAC;QACD,aAAa,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;YACpC,aAAa,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC;gBACnD,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,kFAAkF;gBAClF,kEAAkE;YACpE,CAAC;QACH,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC;IAED,SAAS,gBAAgB,CAAC,QAAgB;QACxC,IAAI,oBAAoB,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;YAC/C,eAAe,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,SAAS,OAAO;QACd,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,YAAY,CAAC,aAAa,CAAC,CAAC;YAC5B,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * OpenAPI spec parser wrapping @redocly/openapi-core.
3
+ *
4
+ * Resolves $ref pointers via Redocly's `bundle()`, producing a fully
5
+ * dereferenced document ready for transformation. Supports OpenAPI 3.0
6
+ * and 3.1 specifications.
7
+ *
8
+ * @module
9
+ */
10
+ import type { ParsedOpenApiSpec } from "./types.js";
11
+ /**
12
+ * Parse an OpenAPI spec file and produce a structured `ParsedOpenApiSpec`.
13
+ *
14
+ * 1. Validates the file exists on disk
15
+ * 2. Uses `@redocly/openapi-core` `bundle()` to resolve `$ref` pointers
16
+ * 3. Detects OpenAPI version (3.0 or 3.1)
17
+ * 4. Passes the parsed document to the transformer
18
+ *
19
+ * @param specPath - Absolute or relative path to an OpenAPI YAML/JSON spec
20
+ * @returns Parsed and transformed spec data
21
+ * @throws {SpecglassError} If the file is missing, unparseable, or not an OpenAPI document
22
+ */
23
+ export declare function parseOpenApiSpec(specPath: string): Promise<ParsedOpenApiSpec>;
24
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/openapi/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,iBAAiB,CAAC,CAgD5B"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * OpenAPI spec parser wrapping @redocly/openapi-core.
3
+ *
4
+ * Resolves $ref pointers via Redocly's `bundle()`, producing a fully
5
+ * dereferenced document ready for transformation. Supports OpenAPI 3.0
6
+ * and 3.1 specifications.
7
+ *
8
+ * @module
9
+ */
10
+ import { resolve } from "node:path";
11
+ import { existsSync } from "node:fs";
12
+ import { bundle, createConfig } from "@redocly/openapi-core";
13
+ import { SpecglassError } from "../errors/specglass-error.js";
14
+ import { transformSpec } from "./transformer.js";
15
+ /**
16
+ * Parse an OpenAPI spec file and produce a structured `ParsedOpenApiSpec`.
17
+ *
18
+ * 1. Validates the file exists on disk
19
+ * 2. Uses `@redocly/openapi-core` `bundle()` to resolve `$ref` pointers
20
+ * 3. Detects OpenAPI version (3.0 or 3.1)
21
+ * 4. Passes the parsed document to the transformer
22
+ *
23
+ * @param specPath - Absolute or relative path to an OpenAPI YAML/JSON spec
24
+ * @returns Parsed and transformed spec data
25
+ * @throws {SpecglassError} If the file is missing, unparseable, or not an OpenAPI document
26
+ */
27
+ export async function parseOpenApiSpec(specPath) {
28
+ // Detect if path is a remote URL
29
+ const isUrl = specPath.startsWith("http://") || specPath.startsWith("https://");
30
+ const ref = isUrl ? specPath : resolve(specPath);
31
+ // Pre-check: for local files, does the file exist?
32
+ if (!isUrl && !existsSync(ref)) {
33
+ throw new SpecglassError(`OpenAPI spec file not found: ${specPath}`, "OPENAPI_PARSE_ERROR", ref, undefined, "Check that the file path is correct and the file exists.");
34
+ }
35
+ let parsed;
36
+ try {
37
+ const config = await createConfig({});
38
+ const result = await bundle({ ref, config });
39
+ parsed = result.bundle.parsed;
40
+ }
41
+ catch (error) {
42
+ const message = error instanceof Error ? error.message : "Unknown parsing error";
43
+ throw new SpecglassError(`Failed to parse OpenAPI spec: ${message}`, "OPENAPI_PARSE_ERROR", ref, undefined, "Check that the file is valid YAML/JSON and conforms to OpenAPI 3.x");
44
+ }
45
+ // Validate this is actually an OpenAPI document
46
+ const openapiVersion = parsed?.openapi;
47
+ if (typeof openapiVersion !== "string" || !openapiVersion.startsWith("3.")) {
48
+ throw new SpecglassError(`File is not an OpenAPI 3.x specification: ${specPath}`, "OPENAPI_PARSE_ERROR", ref, undefined, `Expected an "openapi" field starting with "3." but got ${JSON.stringify(openapiVersion)}. ` +
49
+ "Ensure the file is a valid OpenAPI 3.0 or 3.1 specification.");
50
+ }
51
+ return transformSpec(parsed);
52
+ }
53
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/openapi/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB;IAEhB,iCAAiC;IACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAChF,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEjD,mDAAmD;IACnD,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,cAAc,CACtB,gCAAgC,QAAQ,EAAE,EAC1C,qBAAqB,EACrB,GAAG,EACH,SAAS,EACT,0DAA0D,CAC3D,CAAC;IACJ,CAAC;IAED,IAAI,MAA+B,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7C,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAiC,CAAC;IAC3D,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;QACnE,MAAM,IAAI,cAAc,CACtB,iCAAiC,OAAO,EAAE,EAC1C,qBAAqB,EACrB,GAAG,EACH,SAAS,EACT,oEAAoE,CACrE,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,MAAM,cAAc,GAAG,MAAM,EAAE,OAAO,CAAC;IACvC,IAAI,OAAO,cAAc,KAAK,QAAQ,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,cAAc,CACtB,6CAA6C,QAAQ,EAAE,EACvD,qBAAqB,EACrB,GAAG,EACH,SAAS,EACT,0DAA0D,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI;YAC1F,8DAA8D,CACjE,CAAC;IACJ,CAAC;IAED,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * OpenAPI document transformer.
3
+ *
4
+ * Converts a raw (dereferenced) OpenAPI document into the typed
5
+ * `ParsedOpenApiSpec` data model. Each operation is transformed into
6
+ * an `ApiEndpoint`; failures on individual endpoints produce
7
+ * `ApiEndpointError` objects instead of aborting the entire spec (FR40).
8
+ *
9
+ * @module
10
+ */
11
+ import type { ParsedOpenApiSpec } from "./types.js";
12
+ /**
13
+ * Transform a raw dereferenced OpenAPI document into a `ParsedOpenApiSpec`.
14
+ *
15
+ * @param document - The parsed OpenAPI document from @redocly/openapi-core
16
+ * @returns Structured spec with endpoints, errors, security schemes, and servers
17
+ */
18
+ export declare function transformSpec(document: Record<string, unknown>): ParsedOpenApiSpec;
19
+ //# sourceMappingURL=transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../../src/openapi/transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EASV,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAcpB;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,iBAAiB,CA+CnB"}