@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.
- package/dist/config/defaults.d.ts +4 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +31 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/define-config.d.ts +17 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +55 -0
- package/dist/config/define-config.js.map +1 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +74 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +366 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +109 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/content/frontmatter-schema.d.ts +53 -0
- package/dist/content/frontmatter-schema.d.ts.map +1 -0
- package/dist/content/frontmatter-schema.js +27 -0
- package/dist/content/frontmatter-schema.js.map +1 -0
- package/dist/content/mdx-loader.d.ts +93 -0
- package/dist/content/mdx-loader.d.ts.map +1 -0
- package/dist/content/mdx-loader.js +97 -0
- package/dist/content/mdx-loader.js.map +1 -0
- package/dist/content/openapi-loader.d.ts +40 -0
- package/dist/content/openapi-loader.d.ts.map +1 -0
- package/dist/content/openapi-loader.js +58 -0
- package/dist/content/openapi-loader.js.map +1 -0
- package/dist/content/rehype-code-blocks.d.ts +15 -0
- package/dist/content/rehype-code-blocks.d.ts.map +1 -0
- package/dist/content/rehype-code-blocks.js +84 -0
- package/dist/content/rehype-code-blocks.js.map +1 -0
- package/dist/errors/specglass-error.d.ts +12 -0
- package/dist/errors/specglass-error.d.ts.map +1 -0
- package/dist/errors/specglass-error.js +19 -0
- package/dist/errors/specglass-error.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.d.ts +41 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +276 -0
- package/dist/integration.js.map +1 -0
- package/dist/navigation/builder.d.ts +24 -0
- package/dist/navigation/builder.d.ts.map +1 -0
- package/dist/navigation/builder.js +169 -0
- package/dist/navigation/builder.js.map +1 -0
- package/dist/navigation/index.d.ts +7 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +6 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/meta-parser.d.ts +9 -0
- package/dist/navigation/meta-parser.d.ts.map +1 -0
- package/dist/navigation/meta-parser.js +59 -0
- package/dist/navigation/meta-parser.js.map +1 -0
- package/dist/navigation/meta-schema.d.ts +77 -0
- package/dist/navigation/meta-schema.d.ts.map +1 -0
- package/dist/navigation/meta-schema.js +31 -0
- package/dist/navigation/meta-schema.js.map +1 -0
- package/dist/navigation/watcher.d.ts +44 -0
- package/dist/navigation/watcher.d.ts.map +1 -0
- package/dist/navigation/watcher.js +81 -0
- package/dist/navigation/watcher.js.map +1 -0
- package/dist/openapi/parser.d.ts +24 -0
- package/dist/openapi/parser.d.ts.map +1 -0
- package/dist/openapi/parser.js +53 -0
- package/dist/openapi/parser.js.map +1 -0
- package/dist/openapi/transformer.d.ts +19 -0
- package/dist/openapi/transformer.d.ts.map +1 -0
- package/dist/openapi/transformer.js +294 -0
- package/dist/openapi/transformer.js.map +1 -0
- package/dist/openapi/types.d.ts +109 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/dist/openapi/types.js +11 -0
- package/dist/openapi/types.js.map +1 -0
- package/dist/openapi/utils.d.ts +26 -0
- package/dist/openapi/utils.d.ts.map +1 -0
- package/dist/openapi/utils.js +34 -0
- package/dist/openapi/utils.js.map +1 -0
- package/dist/types/config.d.ts +7 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/navigation.d.ts +62 -0
- package/dist/types/navigation.d.ts.map +1 -0
- package/dist/types/navigation.js +2 -0
- package/dist/types/navigation.js.map +1 -0
- package/dist/virtual/modules.d.ts +34 -0
- package/dist/virtual/modules.d.ts.map +1 -0
- package/dist/virtual/modules.js +37 -0
- package/dist/virtual/modules.js.map +1 -0
- package/package.json +51 -0
- package/src/pages/[...slug].astro +55 -0
- 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"}
|