sourcey 2.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/LICENSE +23 -0
- package/README.md +254 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +197 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/copy.js +21 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +8 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/scroll-tracker.js +88 -0
- package/dist/client/search.js +164 -0
- package/dist/client/sidebar.js +54 -0
- package/dist/client/tabs.js +51 -0
- package/dist/client/theme-toggle.js +36 -0
- package/dist/components/App.d.ts +15 -0
- package/dist/components/App.d.ts.map +1 -0
- package/dist/components/App.js +13 -0
- package/dist/components/App.js.map +1 -0
- package/dist/components/layout/Head.d.ts +2 -0
- package/dist/components/layout/Head.d.ts.map +1 -0
- package/dist/components/layout/Head.js +29 -0
- package/dist/components/layout/Head.js.map +1 -0
- package/dist/components/layout/Header.d.ts +13 -0
- package/dist/components/layout/Header.d.ts.map +1 -0
- package/dist/components/layout/Header.js +38 -0
- package/dist/components/layout/Header.js.map +1 -0
- package/dist/components/layout/Page.d.ts +2 -0
- package/dist/components/layout/Page.d.ts.map +1 -0
- package/dist/components/layout/Page.js +29 -0
- package/dist/components/layout/Page.js.map +1 -0
- package/dist/components/layout/Sidebar.d.ts +9 -0
- package/dist/components/layout/Sidebar.d.ts.map +1 -0
- package/dist/components/layout/Sidebar.js +41 -0
- package/dist/components/layout/Sidebar.js.map +1 -0
- package/dist/components/layout/TableOfContents.d.ts +10 -0
- package/dist/components/layout/TableOfContents.d.ts.map +1 -0
- package/dist/components/layout/TableOfContents.js +12 -0
- package/dist/components/layout/TableOfContents.js.map +1 -0
- package/dist/components/openapi/CodeSamples.d.ts +11 -0
- package/dist/components/openapi/CodeSamples.d.ts.map +1 -0
- package/dist/components/openapi/CodeSamples.js +16 -0
- package/dist/components/openapi/CodeSamples.js.map +1 -0
- package/dist/components/openapi/Definition.d.ts +11 -0
- package/dist/components/openapi/Definition.d.ts.map +1 -0
- package/dist/components/openapi/Definition.js +12 -0
- package/dist/components/openapi/Definition.js.map +1 -0
- package/dist/components/openapi/EndpointBar.d.ts +12 -0
- package/dist/components/openapi/EndpointBar.d.ts.map +1 -0
- package/dist/components/openapi/EndpointBar.js +22 -0
- package/dist/components/openapi/EndpointBar.js.map +1 -0
- package/dist/components/openapi/Introduction.d.ts +6 -0
- package/dist/components/openapi/Introduction.d.ts.map +1 -0
- package/dist/components/openapi/Introduction.js +14 -0
- package/dist/components/openapi/Introduction.js.map +1 -0
- package/dist/components/openapi/Operation.d.ts +13 -0
- package/dist/components/openapi/Operation.d.ts.map +1 -0
- package/dist/components/openapi/Operation.js +23 -0
- package/dist/components/openapi/Operation.js.map +1 -0
- package/dist/components/openapi/Parameters.d.ts +7 -0
- package/dist/components/openapi/Parameters.d.ts.map +1 -0
- package/dist/components/openapi/Parameters.js +10 -0
- package/dist/components/openapi/Parameters.js.map +1 -0
- package/dist/components/openapi/RequestBody.d.ts +17 -0
- package/dist/components/openapi/RequestBody.d.ts.map +1 -0
- package/dist/components/openapi/RequestBody.js +27 -0
- package/dist/components/openapi/RequestBody.js.map +1 -0
- package/dist/components/openapi/Responses.d.ts +14 -0
- package/dist/components/openapi/Responses.d.ts.map +1 -0
- package/dist/components/openapi/Responses.js +60 -0
- package/dist/components/openapi/Responses.js.map +1 -0
- package/dist/components/openapi/Security.d.ts +14 -0
- package/dist/components/openapi/Security.d.ts.map +1 -0
- package/dist/components/openapi/Security.js +32 -0
- package/dist/components/openapi/Security.js.map +1 -0
- package/dist/components/openapi/Tags.d.ts +8 -0
- package/dist/components/openapi/Tags.d.ts.map +1 -0
- package/dist/components/openapi/Tags.js +10 -0
- package/dist/components/openapi/Tags.js.map +1 -0
- package/dist/components/schema/ExampleView.d.ts +11 -0
- package/dist/components/schema/ExampleView.d.ts.map +1 -0
- package/dist/components/schema/ExampleView.js +15 -0
- package/dist/components/schema/ExampleView.js.map +1 -0
- package/dist/components/schema/SchemaDatatype.d.ts +11 -0
- package/dist/components/schema/SchemaDatatype.d.ts.map +1 -0
- package/dist/components/schema/SchemaDatatype.js +36 -0
- package/dist/components/schema/SchemaDatatype.js.map +1 -0
- package/dist/components/schema/SchemaView.d.ts +14 -0
- package/dist/components/schema/SchemaView.d.ts.map +1 -0
- package/dist/components/schema/SchemaView.js +44 -0
- package/dist/components/schema/SchemaView.js.map +1 -0
- package/dist/components/ui/Badge.d.ts +11 -0
- package/dist/components/ui/Badge.d.ts.map +1 -0
- package/dist/components/ui/Badge.js +14 -0
- package/dist/components/ui/Badge.js.map +1 -0
- package/dist/components/ui/Markdown.d.ts +8 -0
- package/dist/components/ui/Markdown.d.ts.map +1 -0
- package/dist/components/ui/Markdown.js +13 -0
- package/dist/components/ui/Markdown.js.map +1 -0
- package/dist/components/ui/SectionLabel.d.ts +10 -0
- package/dist/components/ui/SectionLabel.d.ts.map +1 -0
- package/dist/components/ui/SectionLabel.js +9 -0
- package/dist/components/ui/SectionLabel.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +102 -0
- package/dist/config.js.map +1 -0
- package/dist/core/converter.d.ts +9 -0
- package/dist/core/converter.d.ts.map +1 -0
- package/dist/core/converter.js +29 -0
- package/dist/core/converter.js.map +1 -0
- package/dist/core/loader.d.ts +7 -0
- package/dist/core/loader.d.ts.map +1 -0
- package/dist/core/loader.js +92 -0
- package/dist/core/loader.js.map +1 -0
- package/dist/core/markdown-loader.d.ts +29 -0
- package/dist/core/markdown-loader.d.ts.map +1 -0
- package/dist/core/markdown-loader.js +65 -0
- package/dist/core/markdown-loader.js.map +1 -0
- package/dist/core/navigation.d.ts +51 -0
- package/dist/core/navigation.d.ts.map +1 -0
- package/dist/core/navigation.js +108 -0
- package/dist/core/navigation.js.map +1 -0
- package/dist/core/normalizer.d.ts +7 -0
- package/dist/core/normalizer.d.ts.map +1 -0
- package/dist/core/normalizer.js +472 -0
- package/dist/core/normalizer.js.map +1 -0
- package/dist/core/parser.d.ts +10 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +34 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/search-indexer.d.ts +25 -0
- package/dist/core/search-indexer.d.ts.map +1 -0
- package/dist/core/search-indexer.js +72 -0
- package/dist/core/search-indexer.js.map +1 -0
- package/dist/core/types.d.ts +236 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/dev-server.d.ts +17 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/dev-server.js +202 -0
- package/dist/dev-server.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/dist/renderer/context.d.ts +46 -0
- package/dist/renderer/context.d.ts.map +1 -0
- package/dist/renderer/context.js +22 -0
- package/dist/renderer/context.js.map +1 -0
- package/dist/renderer/html-builder.d.ts +37 -0
- package/dist/renderer/html-builder.d.ts.map +1 -0
- package/dist/renderer/html-builder.js +87 -0
- package/dist/renderer/html-builder.js.map +1 -0
- package/dist/renderer/static-renderer.d.ts +10 -0
- package/dist/renderer/static-renderer.d.ts.map +1 -0
- package/dist/renderer/static-renderer.js +17 -0
- package/dist/renderer/static-renderer.js.map +1 -0
- package/dist/themes/default/main.css +61 -0
- package/dist/themes/default/sourcey.css +425 -0
- package/dist/utils/code-samples.d.ts +8 -0
- package/dist/utils/code-samples.d.ts.map +1 -0
- package/dist/utils/code-samples.js +84 -0
- package/dist/utils/code-samples.js.map +1 -0
- package/dist/utils/example-generator.d.ts +12 -0
- package/dist/utils/example-generator.d.ts.map +1 -0
- package/dist/utils/example-generator.js +123 -0
- package/dist/utils/example-generator.js.map +1 -0
- package/dist/utils/highlighter.d.ts +10 -0
- package/dist/utils/highlighter.d.ts.map +1 -0
- package/dist/utils/highlighter.js +51 -0
- package/dist/utils/highlighter.js.map +1 -0
- package/dist/utils/html-id.d.ts +6 -0
- package/dist/utils/html-id.d.ts.map +1 -0
- package/dist/utils/html-id.js +11 -0
- package/dist/utils/html-id.js.map +1 -0
- package/dist/utils/http.d.ts +14 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +97 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/markdown.d.ts +9 -0
- package/dist/utils/markdown.d.ts.map +1 -0
- package/dist/utils/markdown.js +18 -0
- package/dist/utils/markdown.js.map +1 -0
- package/dist/vite-plugin.d.ts +16 -0
- package/dist/vite-plugin.d.ts.map +1 -0
- package/dist/vite-plugin.js +92 -0
- package/dist/vite-plugin.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { NormalizedSpec } from "./types.js";
|
|
2
|
+
import type { NavigationTab } from "../config.js";
|
|
3
|
+
import type { MarkdownPage } from "./markdown-loader.js";
|
|
4
|
+
export interface SiteNavigation {
|
|
5
|
+
tabs: SiteTab[];
|
|
6
|
+
activeTabSlug: string;
|
|
7
|
+
activePageSlug: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SiteTab {
|
|
10
|
+
label: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
/** Relative URL to this tab's first page (from site root) */
|
|
13
|
+
href: string;
|
|
14
|
+
kind: "spec" | "docs";
|
|
15
|
+
groups: SiteNavGroup[];
|
|
16
|
+
}
|
|
17
|
+
export interface SiteNavGroup {
|
|
18
|
+
label: string;
|
|
19
|
+
items: SiteNavItem[];
|
|
20
|
+
}
|
|
21
|
+
export interface SiteNavItem {
|
|
22
|
+
label: string;
|
|
23
|
+
/** Relative URL to this item (from site root) */
|
|
24
|
+
href: string;
|
|
25
|
+
/** Unique ID for active-state matching */
|
|
26
|
+
id: string;
|
|
27
|
+
/** HTTP method for OpenAPI operations (colored dot in sidebar) */
|
|
28
|
+
method?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build a navigation tab from an OpenAPI spec.
|
|
32
|
+
* Extracts the same structure currently hardcoded in Sidebar.tsx:
|
|
33
|
+
* Introduction + Authentication → tag groups with operations → Models.
|
|
34
|
+
* All hrefs are #anchor links (single-page spec rendering).
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildNavFromSpec(spec: NormalizedSpec, tabSlug: string): SiteTab;
|
|
37
|
+
/**
|
|
38
|
+
* Build a navigation tab from markdown pages.
|
|
39
|
+
* Groups come from the config; items come from loaded page data.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildNavFromPages(tabConfig: NavigationTab, pagesByPath: Map<string, MarkdownPage>): SiteTab;
|
|
42
|
+
/**
|
|
43
|
+
* Assemble a SiteNavigation from a list of tabs.
|
|
44
|
+
* Defaults to the first tab and first page as active.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildSiteNavigation(tabs: SiteTab[]): SiteNavigation;
|
|
47
|
+
/**
|
|
48
|
+
* Create a copy of the navigation with a specific page marked as active.
|
|
49
|
+
*/
|
|
50
|
+
export declare function withActivePage(nav: SiteNavigation, tabSlug: string, pageSlug: string): SiteNavigation;
|
|
51
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/core/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOzD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CA+CT;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,aAAa,EACxB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACrC,OAAO,CA8BT;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CASnE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,cAAc,CAEhB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { htmlId } from "../utils/html-id.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Builders
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
/**
|
|
6
|
+
* Build a navigation tab from an OpenAPI spec.
|
|
7
|
+
* Extracts the same structure currently hardcoded in Sidebar.tsx:
|
|
8
|
+
* Introduction + Authentication → tag groups with operations → Models.
|
|
9
|
+
* All hrefs are #anchor links (single-page spec rendering).
|
|
10
|
+
*/
|
|
11
|
+
export function buildNavFromSpec(spec, tabSlug) {
|
|
12
|
+
const basePath = `${tabSlug}/index.html`;
|
|
13
|
+
const groups = [];
|
|
14
|
+
// Intro group
|
|
15
|
+
const introItems = [
|
|
16
|
+
{ label: "Introduction", href: `${basePath}#introduction`, id: "introduction" },
|
|
17
|
+
];
|
|
18
|
+
if (Object.keys(spec.securitySchemes).length > 0) {
|
|
19
|
+
introItems.push({
|
|
20
|
+
label: "Authentication",
|
|
21
|
+
href: `${basePath}#authentication`,
|
|
22
|
+
id: "authentication",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
groups.push({ label: "", items: introItems });
|
|
26
|
+
// Tag groups with operations
|
|
27
|
+
for (const tag of spec.tags) {
|
|
28
|
+
if (tag.hidden)
|
|
29
|
+
continue;
|
|
30
|
+
const items = tag.operations.map((op) => ({
|
|
31
|
+
label: op.summary ?? `${op.method.toUpperCase()} ${op.path}`,
|
|
32
|
+
href: `${basePath}#operation-${htmlId(op.path)}-${htmlId(op.method)}`,
|
|
33
|
+
id: `operation-${htmlId(op.path)}-${htmlId(op.method)}`,
|
|
34
|
+
method: op.method,
|
|
35
|
+
}));
|
|
36
|
+
groups.push({ label: tag.name, items });
|
|
37
|
+
}
|
|
38
|
+
// Models group
|
|
39
|
+
const schemaNames = Object.keys(spec.schemas);
|
|
40
|
+
if (schemaNames.length > 0) {
|
|
41
|
+
const items = schemaNames.map((name) => ({
|
|
42
|
+
label: name,
|
|
43
|
+
href: `${basePath}#definition-${htmlId(name)}`,
|
|
44
|
+
id: `definition-${htmlId(name)}`,
|
|
45
|
+
}));
|
|
46
|
+
groups.push({ label: "Models", items });
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
label: tabSlug,
|
|
50
|
+
slug: tabSlug,
|
|
51
|
+
href: basePath,
|
|
52
|
+
kind: "spec",
|
|
53
|
+
groups,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build a navigation tab from markdown pages.
|
|
58
|
+
* Groups come from the config; items come from loaded page data.
|
|
59
|
+
*/
|
|
60
|
+
export function buildNavFromPages(tabConfig, pagesByPath) {
|
|
61
|
+
const groups = [];
|
|
62
|
+
if (tabConfig.groups) {
|
|
63
|
+
for (const groupConfig of tabConfig.groups) {
|
|
64
|
+
const items = [];
|
|
65
|
+
for (const pagePath of groupConfig.pages) {
|
|
66
|
+
const page = pagesByPath.get(pagePath);
|
|
67
|
+
if (!page)
|
|
68
|
+
continue;
|
|
69
|
+
items.push({
|
|
70
|
+
label: page.title,
|
|
71
|
+
href: `${tabConfig.slug}/${page.slug}.html`,
|
|
72
|
+
id: page.slug,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
groups.push({ label: groupConfig.label, items });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// First page href for tab link
|
|
79
|
+
const firstItem = groups[0]?.items[0];
|
|
80
|
+
const href = firstItem?.href ?? `${tabConfig.slug}/`;
|
|
81
|
+
return {
|
|
82
|
+
label: tabConfig.label,
|
|
83
|
+
slug: tabConfig.slug,
|
|
84
|
+
href,
|
|
85
|
+
kind: "docs",
|
|
86
|
+
groups,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Assemble a SiteNavigation from a list of tabs.
|
|
91
|
+
* Defaults to the first tab and first page as active.
|
|
92
|
+
*/
|
|
93
|
+
export function buildSiteNavigation(tabs) {
|
|
94
|
+
const firstTab = tabs[0];
|
|
95
|
+
const firstItem = firstTab?.groups[0]?.items[0];
|
|
96
|
+
return {
|
|
97
|
+
tabs,
|
|
98
|
+
activeTabSlug: firstTab?.slug ?? "",
|
|
99
|
+
activePageSlug: firstItem?.id ?? "",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a copy of the navigation with a specific page marked as active.
|
|
104
|
+
*/
|
|
105
|
+
export function withActivePage(nav, tabSlug, pageSlug) {
|
|
106
|
+
return { ...nav, activeTabSlug: tabSlug, activePageSlug: pageSlug };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/core/navigation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ParsedSpec, NormalizedSpec } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform a fully dereferenced OpenAPI 3.x document into a NormalizedSpec.
|
|
4
|
+
* This is the single point where spec-format-specific logic lives.
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizeSpec(parsed: ParsedSpec): NormalizedSpec;
|
|
7
|
+
//# sourceMappingURL=normalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizer.d.ts","sourceRoot":"","sources":["../../src/core/normalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EACV,cAAc,EAqBf,MAAM,YAAY,CAAC;AAMpB;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAoBhE"}
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
const HTTP_METHODS = [
|
|
2
|
+
"get", "post", "put", "delete", "patch", "options", "head", "trace",
|
|
3
|
+
];
|
|
4
|
+
/**
|
|
5
|
+
* Transform a fully dereferenced OpenAPI 3.x document into a NormalizedSpec.
|
|
6
|
+
* This is the single point where spec-format-specific logic lives.
|
|
7
|
+
*/
|
|
8
|
+
export function normalizeSpec(parsed) {
|
|
9
|
+
const doc = parsed.document;
|
|
10
|
+
const schemas = normalizeSchemas(doc.components?.schemas);
|
|
11
|
+
const securitySchemes = normalizeSecuritySchemes(doc.components?.securitySchemes);
|
|
12
|
+
const servers = normalizeServers(doc.servers);
|
|
13
|
+
const operations = normalizeOperations(doc.paths, doc.security);
|
|
14
|
+
const webhooks = normalizeWebhooks(doc.webhooks);
|
|
15
|
+
const tags = normalizeTags(doc.tags, operations);
|
|
16
|
+
return {
|
|
17
|
+
info: normalizeInfo(doc),
|
|
18
|
+
servers,
|
|
19
|
+
tags,
|
|
20
|
+
operations,
|
|
21
|
+
schemas,
|
|
22
|
+
securitySchemes,
|
|
23
|
+
webhooks,
|
|
24
|
+
externalDocs: normalizeExternalDocs(doc.externalDocs),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// ── Info ───────────────────────────────────────────────────────────
|
|
28
|
+
function normalizeInfo(doc) {
|
|
29
|
+
const info = doc.info ?? {};
|
|
30
|
+
return {
|
|
31
|
+
title: str(info.title, "Untitled API"),
|
|
32
|
+
version: str(info.version, "0.0.0"),
|
|
33
|
+
description: optStr(info.description),
|
|
34
|
+
termsOfService: optStr(info.termsOfService),
|
|
35
|
+
contact: info.contact
|
|
36
|
+
? {
|
|
37
|
+
name: optStr(info.contact.name),
|
|
38
|
+
url: optStr(info.contact.url),
|
|
39
|
+
email: optStr(info.contact.email),
|
|
40
|
+
}
|
|
41
|
+
: undefined,
|
|
42
|
+
license: info.license
|
|
43
|
+
? {
|
|
44
|
+
name: str(info.license.name, ""),
|
|
45
|
+
url: optStr(info.license.url),
|
|
46
|
+
identifier: optStr(info.license.identifier),
|
|
47
|
+
}
|
|
48
|
+
: undefined,
|
|
49
|
+
logo: optStr(info["x-logo"]),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// ── Servers ────────────────────────────────────────────────────────
|
|
53
|
+
function normalizeServers(servers) {
|
|
54
|
+
if (!servers?.length)
|
|
55
|
+
return [{ url: "/" }];
|
|
56
|
+
return servers.map((s) => ({
|
|
57
|
+
url: str(s.url, "/"),
|
|
58
|
+
description: optStr(s.description),
|
|
59
|
+
variables: s.variables
|
|
60
|
+
? normalizeServerVariables(s.variables)
|
|
61
|
+
: undefined,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
function normalizeServerVariables(vars) {
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const [key, v] of Object.entries(vars)) {
|
|
67
|
+
result[key] = {
|
|
68
|
+
default: str(v.default, ""),
|
|
69
|
+
description: optStr(v.description),
|
|
70
|
+
enum: Array.isArray(v.enum) ? v.enum.map(String) : undefined,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
// ── Tags ───────────────────────────────────────────────────────────
|
|
76
|
+
function normalizeTags(rawTags, operations) {
|
|
77
|
+
// Build a map of defined tags
|
|
78
|
+
const tagMap = new Map();
|
|
79
|
+
if (rawTags) {
|
|
80
|
+
for (const t of rawTags) {
|
|
81
|
+
const name = str(t.name, "");
|
|
82
|
+
if (name) {
|
|
83
|
+
tagMap.set(name, {
|
|
84
|
+
name,
|
|
85
|
+
description: optStr(t.description),
|
|
86
|
+
externalDocs: normalizeExternalDocs(t.externalDocs),
|
|
87
|
+
operations: [],
|
|
88
|
+
hidden: t["x-sourcey-hide"] === true,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Assign operations to tags, creating implicit tags as needed
|
|
94
|
+
for (const op of operations) {
|
|
95
|
+
if (op.hidden)
|
|
96
|
+
continue;
|
|
97
|
+
const opTags = op.tags.length > 0 ? op.tags : ["default"];
|
|
98
|
+
for (const tagName of opTags) {
|
|
99
|
+
if (!tagMap.has(tagName)) {
|
|
100
|
+
// Implicit tag creation (legacy behavior from preprocessor.js)
|
|
101
|
+
tagMap.set(tagName, {
|
|
102
|
+
name: tagName,
|
|
103
|
+
operations: [],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
tagMap.get(tagName).operations.push(op);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Filter out tags with no operations (unless they have a description)
|
|
110
|
+
return Array.from(tagMap.values()).filter((t) => t.operations.length > 0 || t.description);
|
|
111
|
+
}
|
|
112
|
+
// ── Operations ─────────────────────────────────────────────────────
|
|
113
|
+
function normalizeOperations(paths, globalSecurity) {
|
|
114
|
+
if (!paths)
|
|
115
|
+
return [];
|
|
116
|
+
const operations = [];
|
|
117
|
+
for (const [path, pathItem] of Object.entries(paths)) {
|
|
118
|
+
const pathParams = normalizeParameters(pathItem.parameters);
|
|
119
|
+
for (const method of HTTP_METHODS) {
|
|
120
|
+
const opRaw = pathItem[method];
|
|
121
|
+
if (!opRaw)
|
|
122
|
+
continue;
|
|
123
|
+
const opParams = normalizeParameters(opRaw.parameters);
|
|
124
|
+
// Merge path-level + operation-level params, deduping by name+in
|
|
125
|
+
const mergedParams = deduplicateParameters([...pathParams, ...opParams]);
|
|
126
|
+
const op = {
|
|
127
|
+
operationId: optStr(opRaw.operationId),
|
|
128
|
+
summary: optStr(opRaw.summary),
|
|
129
|
+
description: optStr(opRaw.description),
|
|
130
|
+
method,
|
|
131
|
+
path,
|
|
132
|
+
tags: Array.isArray(opRaw.tags) ? opRaw.tags.map(String) : [],
|
|
133
|
+
parameters: mergedParams,
|
|
134
|
+
requestBody: normalizeRequestBody(opRaw.requestBody),
|
|
135
|
+
responses: normalizeResponses(opRaw.responses),
|
|
136
|
+
security: normalizeSecurityRequirements(opRaw.security, globalSecurity),
|
|
137
|
+
deprecated: opRaw.deprecated === true,
|
|
138
|
+
servers: opRaw.servers
|
|
139
|
+
? normalizeServers(opRaw.servers)
|
|
140
|
+
: undefined,
|
|
141
|
+
externalDocs: normalizeExternalDocs(opRaw.externalDocs),
|
|
142
|
+
callbacks: normalizeCallbacks(opRaw.callbacks),
|
|
143
|
+
hidden: opRaw["x-sourcey-hide"] === true,
|
|
144
|
+
codeSamples: normalizeCodeSamples(opRaw["x-sourcey-code-samples"], opRaw["x-code-samples"]),
|
|
145
|
+
};
|
|
146
|
+
operations.push(op);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return operations;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Deduplicate parameters by (name, in) — operation-level params
|
|
153
|
+
* override path-level params with the same identity.
|
|
154
|
+
*/
|
|
155
|
+
function deduplicateParameters(params) {
|
|
156
|
+
const seen = new Map();
|
|
157
|
+
// Process in order: path-level first, then operation-level.
|
|
158
|
+
// Later entries (operation-level) override earlier ones (path-level).
|
|
159
|
+
for (const p of params) {
|
|
160
|
+
seen.set(`${p.in}:${p.name}`, p);
|
|
161
|
+
}
|
|
162
|
+
return Array.from(seen.values());
|
|
163
|
+
}
|
|
164
|
+
function normalizeParameters(params) {
|
|
165
|
+
if (!params)
|
|
166
|
+
return [];
|
|
167
|
+
return params.map((p) => ({
|
|
168
|
+
name: str(p.name, ""),
|
|
169
|
+
in: str(p.in, "query"),
|
|
170
|
+
description: optStr(p.description),
|
|
171
|
+
required: p.required === true,
|
|
172
|
+
deprecated: p.deprecated === true,
|
|
173
|
+
schema: p.schema
|
|
174
|
+
? normalizeSchema(p.schema)
|
|
175
|
+
: undefined,
|
|
176
|
+
example: p.example,
|
|
177
|
+
examples: p.examples
|
|
178
|
+
? normalizeExamples(p.examples)
|
|
179
|
+
: undefined,
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
function normalizeRequestBody(body) {
|
|
183
|
+
if (!body)
|
|
184
|
+
return undefined;
|
|
185
|
+
return {
|
|
186
|
+
description: optStr(body.description),
|
|
187
|
+
required: body.required === true,
|
|
188
|
+
content: normalizeContent(body.content),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function normalizeContent(content) {
|
|
192
|
+
if (!content)
|
|
193
|
+
return {};
|
|
194
|
+
const result = {};
|
|
195
|
+
for (const [mediaType, value] of Object.entries(content)) {
|
|
196
|
+
result[mediaType] = {
|
|
197
|
+
schema: value.schema
|
|
198
|
+
? normalizeSchema(value.schema)
|
|
199
|
+
: undefined,
|
|
200
|
+
example: value.example,
|
|
201
|
+
examples: value.examples
|
|
202
|
+
? normalizeExamples(value.examples)
|
|
203
|
+
: undefined,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
function normalizeResponses(responses) {
|
|
209
|
+
if (!responses)
|
|
210
|
+
return [];
|
|
211
|
+
return Object.entries(responses).map(([statusCode, r]) => ({
|
|
212
|
+
statusCode,
|
|
213
|
+
description: str(r.description, ""),
|
|
214
|
+
content: r.content
|
|
215
|
+
? normalizeContent(r.content)
|
|
216
|
+
: undefined,
|
|
217
|
+
headers: r.headers
|
|
218
|
+
? normalizeResponseHeaders(r.headers)
|
|
219
|
+
: undefined,
|
|
220
|
+
links: r.links
|
|
221
|
+
? normalizeLinks(r.links)
|
|
222
|
+
: undefined,
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
function normalizeResponseHeaders(headers) {
|
|
226
|
+
const result = {};
|
|
227
|
+
for (const [name, h] of Object.entries(headers)) {
|
|
228
|
+
result[name] = {
|
|
229
|
+
name,
|
|
230
|
+
in: "header",
|
|
231
|
+
description: optStr(h.description),
|
|
232
|
+
required: h.required === true,
|
|
233
|
+
deprecated: h.deprecated === true,
|
|
234
|
+
schema: h.schema
|
|
235
|
+
? normalizeSchema(h.schema)
|
|
236
|
+
: undefined,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
function normalizeLinks(links) {
|
|
242
|
+
const result = {};
|
|
243
|
+
for (const [name, l] of Object.entries(links)) {
|
|
244
|
+
result[name] = {
|
|
245
|
+
operationId: optStr(l.operationId),
|
|
246
|
+
operationRef: optStr(l.operationRef),
|
|
247
|
+
description: optStr(l.description),
|
|
248
|
+
parameters: l.parameters,
|
|
249
|
+
requestBody: l.requestBody,
|
|
250
|
+
server: l.server
|
|
251
|
+
? normalizeServers([l.server])[0]
|
|
252
|
+
: undefined,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
function normalizeCallbacks(callbacks) {
|
|
258
|
+
if (!callbacks)
|
|
259
|
+
return undefined;
|
|
260
|
+
const result = {};
|
|
261
|
+
for (const [expression, pathItem] of Object.entries(callbacks)) {
|
|
262
|
+
result[expression] = {
|
|
263
|
+
expression,
|
|
264
|
+
operations: normalizeOperations({ [expression]: pathItem }),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
function normalizeSecurityRequirements(opSecurity, globalSecurity) {
|
|
270
|
+
// Operation security overrides global
|
|
271
|
+
return (opSecurity ?? globalSecurity ?? []);
|
|
272
|
+
}
|
|
273
|
+
function normalizeCodeSamples(sourceySamples, genericSamples) {
|
|
274
|
+
const samples = sourceySamples ?? genericSamples;
|
|
275
|
+
if (!samples?.length)
|
|
276
|
+
return undefined;
|
|
277
|
+
return samples.map((s) => ({
|
|
278
|
+
lang: str(s.lang, "text"),
|
|
279
|
+
label: optStr(s.label),
|
|
280
|
+
source: str(s.source, ""),
|
|
281
|
+
}));
|
|
282
|
+
}
|
|
283
|
+
// ── Schemas ────────────────────────────────────────────────────────
|
|
284
|
+
function normalizeSchemas(schemas) {
|
|
285
|
+
if (!schemas)
|
|
286
|
+
return {};
|
|
287
|
+
const result = {};
|
|
288
|
+
for (const [name, s] of Object.entries(schemas)) {
|
|
289
|
+
result[name] = normalizeSchema(s, name);
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
function normalizeSchema(schema, name) {
|
|
294
|
+
// Handle nullable: OpenAPI 3.0 uses x-nullable or nullable,
|
|
295
|
+
// OpenAPI 3.1 uses type: ["string", "null"]
|
|
296
|
+
let type = schema.type;
|
|
297
|
+
let nullable = schema.nullable === true || schema["x-nullable"] === true;
|
|
298
|
+
if (Array.isArray(type)) {
|
|
299
|
+
const nonNullTypes = type.filter((t) => t !== "null");
|
|
300
|
+
if (nonNullTypes.length < type.length) {
|
|
301
|
+
nullable = true;
|
|
302
|
+
}
|
|
303
|
+
type = nonNullTypes.length === 1 ? nonNullTypes[0] : nonNullTypes;
|
|
304
|
+
}
|
|
305
|
+
const result = {
|
|
306
|
+
name,
|
|
307
|
+
type,
|
|
308
|
+
format: optStr(schema.format),
|
|
309
|
+
title: optStr(schema.title),
|
|
310
|
+
description: optStr(schema.description),
|
|
311
|
+
default: schema.default,
|
|
312
|
+
enum: Array.isArray(schema.enum) ? schema.enum : undefined,
|
|
313
|
+
const: schema.const,
|
|
314
|
+
nullable,
|
|
315
|
+
readOnly: schema.readOnly === true,
|
|
316
|
+
writeOnly: schema.writeOnly === true,
|
|
317
|
+
deprecated: schema.deprecated === true,
|
|
318
|
+
example: schema.example,
|
|
319
|
+
examples: Array.isArray(schema.examples) ? schema.examples : undefined,
|
|
320
|
+
refName: optStr(schema["x-ref-name"]),
|
|
321
|
+
};
|
|
322
|
+
// Object properties
|
|
323
|
+
if (schema.properties) {
|
|
324
|
+
result.properties = {};
|
|
325
|
+
for (const [key, val] of Object.entries(schema.properties)) {
|
|
326
|
+
result.properties[key] = normalizeSchema(val);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (schema.additionalProperties !== undefined) {
|
|
330
|
+
result.additionalProperties =
|
|
331
|
+
typeof schema.additionalProperties === "boolean"
|
|
332
|
+
? schema.additionalProperties
|
|
333
|
+
: normalizeSchema(schema.additionalProperties);
|
|
334
|
+
}
|
|
335
|
+
if (Array.isArray(schema.required)) {
|
|
336
|
+
result.required = schema.required.map(String);
|
|
337
|
+
}
|
|
338
|
+
// Array items
|
|
339
|
+
if (schema.items) {
|
|
340
|
+
result.items = normalizeSchema(schema.items);
|
|
341
|
+
}
|
|
342
|
+
if (schema.minItems !== undefined)
|
|
343
|
+
result.minItems = Number(schema.minItems);
|
|
344
|
+
if (schema.maxItems !== undefined)
|
|
345
|
+
result.maxItems = Number(schema.maxItems);
|
|
346
|
+
if (schema.uniqueItems === true)
|
|
347
|
+
result.uniqueItems = true;
|
|
348
|
+
// Numeric constraints
|
|
349
|
+
if (schema.minimum !== undefined)
|
|
350
|
+
result.minimum = Number(schema.minimum);
|
|
351
|
+
if (schema.maximum !== undefined)
|
|
352
|
+
result.maximum = Number(schema.maximum);
|
|
353
|
+
if (schema.exclusiveMinimum !== undefined) {
|
|
354
|
+
result.exclusiveMinimum = schema.exclusiveMinimum;
|
|
355
|
+
}
|
|
356
|
+
if (schema.exclusiveMaximum !== undefined) {
|
|
357
|
+
result.exclusiveMaximum = schema.exclusiveMaximum;
|
|
358
|
+
}
|
|
359
|
+
if (schema.multipleOf !== undefined)
|
|
360
|
+
result.multipleOf = Number(schema.multipleOf);
|
|
361
|
+
// String constraints
|
|
362
|
+
if (schema.minLength !== undefined)
|
|
363
|
+
result.minLength = Number(schema.minLength);
|
|
364
|
+
if (schema.maxLength !== undefined)
|
|
365
|
+
result.maxLength = Number(schema.maxLength);
|
|
366
|
+
if (schema.pattern !== undefined)
|
|
367
|
+
result.pattern = String(schema.pattern);
|
|
368
|
+
// Composition
|
|
369
|
+
if (Array.isArray(schema.allOf)) {
|
|
370
|
+
result.allOf = schema.allOf.map((s) => normalizeSchema(s));
|
|
371
|
+
}
|
|
372
|
+
if (Array.isArray(schema.anyOf)) {
|
|
373
|
+
result.anyOf = schema.anyOf.map((s) => normalizeSchema(s));
|
|
374
|
+
}
|
|
375
|
+
if (Array.isArray(schema.oneOf)) {
|
|
376
|
+
result.oneOf = schema.oneOf.map((s) => normalizeSchema(s));
|
|
377
|
+
}
|
|
378
|
+
if (schema.not) {
|
|
379
|
+
result.not = normalizeSchema(schema.not);
|
|
380
|
+
}
|
|
381
|
+
if (schema.discriminator) {
|
|
382
|
+
const d = schema.discriminator;
|
|
383
|
+
result.discriminator = {
|
|
384
|
+
propertyName: str(d.propertyName, ""),
|
|
385
|
+
mapping: d.mapping,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
// External docs
|
|
389
|
+
if (schema.externalDocs) {
|
|
390
|
+
result.externalDocs = normalizeExternalDocs(schema.externalDocs);
|
|
391
|
+
}
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
// ── Security Schemes ───────────────────────────────────────────────
|
|
395
|
+
function normalizeSecuritySchemes(schemes) {
|
|
396
|
+
if (!schemes)
|
|
397
|
+
return {};
|
|
398
|
+
const result = {};
|
|
399
|
+
for (const [name, s] of Object.entries(schemes)) {
|
|
400
|
+
const raw = s;
|
|
401
|
+
result[name] = {
|
|
402
|
+
type: str(raw.type, "apiKey"),
|
|
403
|
+
name: optStr(raw.name),
|
|
404
|
+
description: optStr(raw.description),
|
|
405
|
+
in: optStr(raw.in),
|
|
406
|
+
scheme: optStr(raw.scheme),
|
|
407
|
+
bearerFormat: optStr(raw.bearerFormat),
|
|
408
|
+
flows: raw.flows
|
|
409
|
+
? normalizeOAuthFlows(raw.flows)
|
|
410
|
+
: undefined,
|
|
411
|
+
openIdConnectUrl: optStr(raw.openIdConnectUrl),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
return result;
|
|
415
|
+
}
|
|
416
|
+
function normalizeOAuthFlows(flows) {
|
|
417
|
+
const result = {};
|
|
418
|
+
for (const flowType of [
|
|
419
|
+
"implicit",
|
|
420
|
+
"password",
|
|
421
|
+
"clientCredentials",
|
|
422
|
+
"authorizationCode",
|
|
423
|
+
]) {
|
|
424
|
+
if (flows[flowType]) {
|
|
425
|
+
result[flowType] = normalizeOAuthFlow(flows[flowType]);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
function normalizeOAuthFlow(flow) {
|
|
431
|
+
return {
|
|
432
|
+
authorizationUrl: optStr(flow.authorizationUrl),
|
|
433
|
+
tokenUrl: optStr(flow.tokenUrl),
|
|
434
|
+
refreshUrl: optStr(flow.refreshUrl),
|
|
435
|
+
scopes: (flow.scopes ?? {}),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
// ── Webhooks ───────────────────────────────────────────────────────
|
|
439
|
+
function normalizeWebhooks(webhooks) {
|
|
440
|
+
if (!webhooks)
|
|
441
|
+
return [];
|
|
442
|
+
return normalizeOperations(webhooks);
|
|
443
|
+
}
|
|
444
|
+
// ── Shared ─────────────────────────────────────────────────────────
|
|
445
|
+
function normalizeExternalDocs(docs) {
|
|
446
|
+
if (!docs?.url)
|
|
447
|
+
return undefined;
|
|
448
|
+
return {
|
|
449
|
+
url: str(docs.url, ""),
|
|
450
|
+
description: optStr(docs.description),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function normalizeExamples(examples) {
|
|
454
|
+
const result = {};
|
|
455
|
+
for (const [name, e] of Object.entries(examples)) {
|
|
456
|
+
result[name] = {
|
|
457
|
+
summary: optStr(e.summary),
|
|
458
|
+
description: optStr(e.description),
|
|
459
|
+
value: e.value,
|
|
460
|
+
externalValue: optStr(e.externalValue),
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
465
|
+
// ── Utility helpers ────────────────────────────────────────────────
|
|
466
|
+
function str(value, fallback) {
|
|
467
|
+
return typeof value === "string" ? value : fallback;
|
|
468
|
+
}
|
|
469
|
+
function optStr(value) {
|
|
470
|
+
return typeof value === "string" ? value : undefined;
|
|
471
|
+
}
|
|
472
|
+
//# sourceMappingURL=normalizer.js.map
|