blodemd 0.0.4 → 0.0.6
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/README.md +12 -1
- package/dev-server/app/[[...slug]]/page.tsx +139 -0
- package/dev-server/app/blodemd-dev/invalidate/route.ts +12 -0
- package/dev-server/app/blodemd-dev/static/[...path]/route.ts +32 -0
- package/dev-server/app/blodemd-dev/version/route.ts +14 -0
- package/dev-server/app/blodemd-internal/proxy/route.ts +86 -0
- package/dev-server/app/error.tsx +24 -0
- package/dev-server/app/globals.css +4 -0
- package/dev-server/app/layout.tsx +38 -0
- package/dev-server/app/not-found.tsx +18 -0
- package/dev-server/app/search/route.ts +17 -0
- package/dev-server/components/dev-reload-script.tsx +86 -0
- package/dev-server/components/providers.tsx +15 -0
- package/dev-server/lib/dev-state.ts +8 -0
- package/dev-server/lib/local-content-source.ts +103 -0
- package/dev-server/lib/local-runtime.tsx +558 -0
- package/dev-server/next.config.js +46 -0
- package/dev-server/package.json +57 -0
- package/dev-server/postcss.config.mjs +7 -0
- package/dev-server/public/glide-variable.woff2 +0 -0
- package/dev-server/tsconfig.json +49 -0
- package/dist/cli.mjs +299 -26
- package/dist/cli.mjs.map +1 -1
- package/docs/app/globals.css +455 -0
- package/docs/components/api/api-playground.tsx +295 -0
- package/docs/components/api/api-reference.tsx +121 -0
- package/docs/components/content/collection-index.tsx +114 -0
- package/docs/components/docs/contextual-menu.tsx +406 -0
- package/docs/components/docs/copy-page-menu.tsx +255 -0
- package/docs/components/docs/doc-header.tsx +192 -0
- package/docs/components/docs/doc-shell.tsx +289 -0
- package/docs/components/docs/doc-sidebar.tsx +206 -0
- package/docs/components/docs/doc-toc.tsx +45 -0
- package/docs/components/docs/mobile-nav.tsx +207 -0
- package/docs/components/mdx/accordion.tsx +83 -0
- package/docs/components/mdx/badge.tsx +79 -0
- package/docs/components/mdx/callout.tsx +88 -0
- package/docs/components/mdx/card.tsx +104 -0
- package/docs/components/mdx/code-block.tsx +75 -0
- package/docs/components/mdx/code-group.tsx +94 -0
- package/docs/components/mdx/color.tsx +87 -0
- package/docs/components/mdx/columns.tsx +25 -0
- package/docs/components/mdx/expandable.tsx +45 -0
- package/docs/components/mdx/field-layout.tsx +77 -0
- package/docs/components/mdx/frame.tsx +23 -0
- package/docs/components/mdx/get-text-content.ts +18 -0
- package/docs/components/mdx/icon.tsx +56 -0
- package/docs/components/mdx/index.tsx +96 -0
- package/docs/components/mdx/installer.tsx +20 -0
- package/docs/components/mdx/panel.tsx +11 -0
- package/docs/components/mdx/param-field.tsx +56 -0
- package/docs/components/mdx/preview.tsx +36 -0
- package/docs/components/mdx/prompt.tsx +63 -0
- package/docs/components/mdx/request-example.tsx +27 -0
- package/docs/components/mdx/response-field.tsx +42 -0
- package/docs/components/mdx/steps.tsx +92 -0
- package/docs/components/mdx/tabs.tsx +88 -0
- package/docs/components/mdx/tile.tsx +43 -0
- package/docs/components/mdx/tooltip.tsx +71 -0
- package/docs/components/mdx/tree.tsx +120 -0
- package/docs/components/mdx/type-table.tsx +71 -0
- package/docs/components/mdx/update.tsx +44 -0
- package/docs/components/mdx/video.tsx +12 -0
- package/docs/components/mdx/view.tsx +66 -0
- package/docs/components/providers.tsx +15 -0
- package/docs/components/ui/breadcrumb.tsx +92 -0
- package/docs/components/ui/button.tsx +90 -0
- package/docs/components/ui/card.tsx +92 -0
- package/docs/components/ui/command.tsx +139 -0
- package/docs/components/ui/dialog.tsx +97 -0
- package/docs/components/ui/field.tsx +237 -0
- package/docs/components/ui/input.tsx +105 -0
- package/docs/components/ui/label.tsx +22 -0
- package/docs/components/ui/popover.tsx +72 -0
- package/docs/components/ui/search.tsx +380 -0
- package/docs/components/ui/separator.tsx +26 -0
- package/docs/components/ui/sheet.tsx +104 -0
- package/docs/components/ui/sidebar.tsx +433 -0
- package/docs/components/ui/theme-toggle.tsx +62 -0
- package/docs/components/ui/tooltip.tsx +53 -0
- package/docs/lib/contextual-options.ts +193 -0
- package/docs/lib/docs-collection.ts +22 -0
- package/docs/lib/mdx.ts +90 -0
- package/docs/lib/navigation.ts +288 -0
- package/docs/lib/openapi.ts +158 -0
- package/docs/lib/routes.ts +10 -0
- package/docs/lib/server-cache.ts +83 -0
- package/docs/lib/shiki.ts +35 -0
- package/docs/lib/theme.ts +29 -0
- package/docs/lib/toc.ts +2 -0
- package/docs/lib/utils.ts +5 -0
- package/package.json +34 -3
- package/packages/@repo/common/dist/index.d.ts +9 -0
- package/packages/@repo/common/dist/index.d.ts.map +1 -0
- package/packages/@repo/common/dist/index.js +42 -0
- package/packages/@repo/common/package.json +34 -0
- package/packages/@repo/common/src/common.unit.test.ts +55 -0
- package/packages/@repo/common/src/index.ts +51 -0
- package/packages/@repo/contracts/dist/api-key.d.ts +30 -0
- package/packages/@repo/contracts/dist/api-key.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/api-key.js +20 -0
- package/packages/@repo/contracts/dist/dates.d.ts +4 -0
- package/packages/@repo/contracts/dist/dates.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/dates.js +2 -0
- package/packages/@repo/contracts/dist/deployment.d.ts +71 -0
- package/packages/@repo/contracts/dist/deployment.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/deployment.js +46 -0
- package/packages/@repo/contracts/dist/domain.d.ts +94 -0
- package/packages/@repo/contracts/dist/domain.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/domain.js +36 -0
- package/packages/@repo/contracts/dist/ids.d.ts +14 -0
- package/packages/@repo/contracts/dist/ids.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/ids.js +10 -0
- package/packages/@repo/contracts/dist/index.d.ts +10 -0
- package/packages/@repo/contracts/dist/index.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/index.js +11 -0
- package/packages/@repo/contracts/dist/pagination.d.ts +23 -0
- package/packages/@repo/contracts/dist/pagination.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/pagination.js +15 -0
- package/packages/@repo/contracts/dist/project.d.ts +25 -0
- package/packages/@repo/contracts/dist/project.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/project.js +23 -0
- package/packages/@repo/contracts/dist/tenant.d.ts +99 -0
- package/packages/@repo/contracts/dist/tenant.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/tenant.js +36 -0
- package/packages/@repo/contracts/dist/user.d.ts +9 -0
- package/packages/@repo/contracts/dist/user.d.ts.map +1 -0
- package/packages/@repo/contracts/dist/user.js +9 -0
- package/packages/@repo/contracts/package.json +37 -0
- package/packages/@repo/contracts/src/api-key.ts +27 -0
- package/packages/@repo/contracts/src/dates.ts +4 -0
- package/packages/@repo/contracts/src/deployment.ts +73 -0
- package/packages/@repo/contracts/src/domain.ts +51 -0
- package/packages/@repo/contracts/src/ids.ts +22 -0
- package/packages/@repo/contracts/src/index.ts +11 -0
- package/packages/@repo/contracts/src/pagination.ts +21 -0
- package/packages/@repo/contracts/src/project.ts +30 -0
- package/packages/@repo/contracts/src/tenant.ts +54 -0
- package/packages/@repo/contracts/src/user.ts +12 -0
- package/packages/@repo/models/dist/docs-config.d.ts +985 -0
- package/packages/@repo/models/dist/docs-config.d.ts.map +1 -0
- package/packages/@repo/models/dist/docs-config.js +548 -0
- package/packages/@repo/models/dist/index.d.ts +3 -0
- package/packages/@repo/models/dist/index.d.ts.map +1 -0
- package/packages/@repo/models/dist/index.js +3 -0
- package/packages/@repo/models/dist/tenant.d.ts +25 -0
- package/packages/@repo/models/dist/tenant.d.ts.map +1 -0
- package/packages/@repo/models/dist/tenant.js +1 -0
- package/packages/@repo/models/package.json +37 -0
- package/packages/@repo/models/src/docs-config.ts +648 -0
- package/packages/@repo/models/src/index.ts +3 -0
- package/packages/@repo/models/src/tenant.ts +29 -0
- package/packages/@repo/prebuild/dist/index.d.ts +2 -0
- package/packages/@repo/prebuild/dist/index.d.ts.map +1 -0
- package/packages/@repo/prebuild/dist/index.js +2 -0
- package/packages/@repo/prebuild/dist/openapi.d.ts +43 -0
- package/packages/@repo/prebuild/dist/openapi.d.ts.map +1 -0
- package/packages/@repo/prebuild/dist/openapi.js +58 -0
- package/packages/@repo/prebuild/package.json +39 -0
- package/packages/@repo/prebuild/src/index.ts +2 -0
- package/packages/@repo/prebuild/src/openapi.ts +116 -0
- package/packages/@repo/previewing/dist/blob-source.d.ts +16 -0
- package/packages/@repo/previewing/dist/blob-source.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/blob-source.js +110 -0
- package/packages/@repo/previewing/dist/content-source.d.ts +12 -0
- package/packages/@repo/previewing/dist/content-source.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/content-source.js +1 -0
- package/packages/@repo/previewing/dist/fs-source.d.ts +11 -0
- package/packages/@repo/previewing/dist/fs-source.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/fs-source.js +79 -0
- package/packages/@repo/previewing/dist/index.d.ts +120 -0
- package/packages/@repo/previewing/dist/index.d.ts.map +1 -0
- package/packages/@repo/previewing/dist/index.js +984 -0
- package/packages/@repo/previewing/package.json +41 -0
- package/packages/@repo/previewing/src/blob-source.ts +167 -0
- package/packages/@repo/previewing/src/content-source.ts +12 -0
- package/packages/@repo/previewing/src/fs-source.ts +111 -0
- package/packages/@repo/previewing/src/index.ts +1490 -0
- package/packages/@repo/previewing/src/index.unit.test.ts +290 -0
- package/packages/@repo/validation/dist/index.d.ts +12 -0
- package/packages/@repo/validation/dist/index.d.ts.map +1 -0
- package/packages/@repo/validation/dist/index.js +30 -0
- package/packages/@repo/validation/package.json +37 -0
- package/packages/@repo/validation/src/index.ts +59 -0
- package/packages/@repo/validation/src/mintlify-docs-schema.json +5016 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { ensureArray, normalizePath } from "@repo/common";
|
|
2
|
+
import type { CollectionConfig, DocsOpenApiSource } from "@repo/models";
|
|
3
|
+
import {
|
|
4
|
+
extractOpenApiOperations,
|
|
5
|
+
openApiIdentifier,
|
|
6
|
+
openApiSlug,
|
|
7
|
+
parseOpenApiSpec,
|
|
8
|
+
} from "@repo/prebuild";
|
|
9
|
+
import type { OpenApiOperation, OpenApiSpec } from "@repo/prebuild";
|
|
10
|
+
import { loadPrebuiltOpenApiIndex } from "@repo/previewing";
|
|
11
|
+
import type { ContentSource, PrebuiltOpenApiEntry } from "@repo/previewing";
|
|
12
|
+
|
|
13
|
+
export interface OpenApiEntry {
|
|
14
|
+
slug: string;
|
|
15
|
+
identifier: string;
|
|
16
|
+
operation: OpenApiOperation;
|
|
17
|
+
spec: OpenApiSpec;
|
|
18
|
+
source: DocsOpenApiSource;
|
|
19
|
+
sourceKey: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface OpenApiRegistry {
|
|
23
|
+
entries: OpenApiEntry[];
|
|
24
|
+
bySlug: Map<string, OpenApiEntry>;
|
|
25
|
+
byIdentifier: Map<string, OpenApiEntry>;
|
|
26
|
+
bySource: Map<string, OpenApiEntry[]>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const toRegistry = (entries: OpenApiEntry[]): OpenApiRegistry => {
|
|
30
|
+
const bySlug = new Map<string, OpenApiEntry>();
|
|
31
|
+
const byIdentifier = new Map<string, OpenApiEntry>();
|
|
32
|
+
const bySource = new Map<string, OpenApiEntry[]>();
|
|
33
|
+
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
bySlug.set(entry.slug, entry);
|
|
36
|
+
byIdentifier.set(entry.identifier, entry);
|
|
37
|
+
if (!bySource.has(entry.sourceKey)) {
|
|
38
|
+
bySource.set(entry.sourceKey, []);
|
|
39
|
+
}
|
|
40
|
+
bySource.get(entry.sourceKey)?.push(entry);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { byIdentifier, bySlug, bySource, entries };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const fromPrebuiltOpenApiEntries = (
|
|
47
|
+
entries: PrebuiltOpenApiEntry[]
|
|
48
|
+
): OpenApiRegistry => toRegistry(entries);
|
|
49
|
+
|
|
50
|
+
const getOpenApiSourceKey = (source: DocsOpenApiSource): string =>
|
|
51
|
+
`${source.source}::${source.directory ?? ""}::${(source.include ?? []).join(
|
|
52
|
+
"|"
|
|
53
|
+
)}`;
|
|
54
|
+
|
|
55
|
+
const toSourceObject = (
|
|
56
|
+
value: string | DocsOpenApiSource
|
|
57
|
+
): DocsOpenApiSource => {
|
|
58
|
+
if (typeof value === "string") {
|
|
59
|
+
return { source: value };
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const collectOpenApiSources = (collection?: CollectionConfig) => {
|
|
65
|
+
const sources: DocsOpenApiSource[] = [];
|
|
66
|
+
|
|
67
|
+
for (const item of ensureArray(collection?.openapi)) {
|
|
68
|
+
if (!item) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
sources.push(toSourceObject(item));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const groups = collection?.navigation?.groups ?? [];
|
|
75
|
+
for (const group of groups) {
|
|
76
|
+
if (!group.openapi) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
sources.push(toSourceObject(group.openapi));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const seen = new Set<string>();
|
|
83
|
+
return sources.filter((source) => {
|
|
84
|
+
const key = getOpenApiSourceKey(source);
|
|
85
|
+
if (seen.has(key)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
seen.add(key);
|
|
89
|
+
return true;
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const buildOpenApiRegistry = async (
|
|
94
|
+
collection: CollectionConfig | undefined,
|
|
95
|
+
contentSource: ContentSource
|
|
96
|
+
): Promise<OpenApiRegistry> => {
|
|
97
|
+
if (!collection || collection.type !== "docs") {
|
|
98
|
+
return toRegistry([]);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const entries: OpenApiEntry[] = [];
|
|
102
|
+
const slugPrefix = normalizePath(collection.slugPrefix ?? "");
|
|
103
|
+
|
|
104
|
+
const sources = collectOpenApiSources(collection);
|
|
105
|
+
const resolved = await Promise.all(
|
|
106
|
+
sources.map(async (source) => {
|
|
107
|
+
const rawSpec = await contentSource.readFile(source.source);
|
|
108
|
+
const spec = parseOpenApiSpec(rawSpec, source.source);
|
|
109
|
+
const directory = source.directory ?? "api";
|
|
110
|
+
const { operations } = extractOpenApiOperations(spec, directory);
|
|
111
|
+
return { directory, operations, source, spec };
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
for (const { directory, operations, source, spec } of resolved) {
|
|
116
|
+
const sourceKey = getOpenApiSourceKey(source);
|
|
117
|
+
const includeIdentifiers = source.include?.length
|
|
118
|
+
? new Set(source.include)
|
|
119
|
+
: null;
|
|
120
|
+
|
|
121
|
+
for (const operation of operations) {
|
|
122
|
+
const identifier = openApiIdentifier(operation.method, operation.path);
|
|
123
|
+
if (includeIdentifiers && !includeIdentifiers.has(identifier)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const baseSlug = normalizePath(
|
|
128
|
+
openApiSlug(operation.method, operation.path, directory)
|
|
129
|
+
);
|
|
130
|
+
const slug = slugPrefix
|
|
131
|
+
? normalizePath(`${slugPrefix}/${baseSlug}`)
|
|
132
|
+
: baseSlug;
|
|
133
|
+
const entry: OpenApiEntry = {
|
|
134
|
+
identifier,
|
|
135
|
+
operation,
|
|
136
|
+
slug: normalizePath(slug),
|
|
137
|
+
source,
|
|
138
|
+
sourceKey,
|
|
139
|
+
spec,
|
|
140
|
+
};
|
|
141
|
+
entries.push(entry);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return toRegistry(entries);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const loadOpenApiRegistry = async (
|
|
149
|
+
collection: CollectionConfig | undefined,
|
|
150
|
+
contentSource: ContentSource
|
|
151
|
+
): Promise<OpenApiRegistry> => {
|
|
152
|
+
const prebuilt = await loadPrebuiltOpenApiIndex(contentSource);
|
|
153
|
+
if (prebuilt) {
|
|
154
|
+
return fromPrebuiltOpenApiEntries(prebuilt);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return await buildOpenApiRegistry(collection, contentSource);
|
|
158
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { normalizePath, withLeadingSlash } from "@repo/common";
|
|
2
|
+
|
|
3
|
+
export const toDocHref = (path: string, basePath = "") => {
|
|
4
|
+
const clean = normalizePath(path);
|
|
5
|
+
const base = basePath ? withLeadingSlash(basePath) : "";
|
|
6
|
+
if (!clean || clean === "index") {
|
|
7
|
+
return base || "/";
|
|
8
|
+
}
|
|
9
|
+
return `${base}/${clean}`.replaceAll(/\/+/g, "/");
|
|
10
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
interface CacheEntry<Value> {
|
|
2
|
+
expiresAt: number;
|
|
3
|
+
value: Promise<Value>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface TimedPromiseCacheOptions {
|
|
7
|
+
maxEntries: number;
|
|
8
|
+
ttlMs: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TimedPromiseCache<Key, Value> {
|
|
12
|
+
clear(): void;
|
|
13
|
+
delete(key: Key): void;
|
|
14
|
+
deleteByPrefix(prefix: string): void;
|
|
15
|
+
getOrCreate(key: Key, factory: () => Promise<Value>): Promise<Value>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const createTimedPromiseCache = <Key, Value>({
|
|
19
|
+
maxEntries,
|
|
20
|
+
ttlMs,
|
|
21
|
+
}: TimedPromiseCacheOptions): TimedPromiseCache<Key, Value> => {
|
|
22
|
+
const entries = new Map<Key, CacheEntry<Value>>();
|
|
23
|
+
|
|
24
|
+
const deleteOldest = () => {
|
|
25
|
+
const oldestKey = entries.keys().next().value as Key | undefined;
|
|
26
|
+
if (oldestKey !== undefined) {
|
|
27
|
+
entries.delete(oldestKey);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const pruneExpired = (now: number) => {
|
|
32
|
+
for (const [key, entry] of entries) {
|
|
33
|
+
if (entry.expiresAt <= now) {
|
|
34
|
+
entries.delete(key);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
clear() {
|
|
41
|
+
entries.clear();
|
|
42
|
+
},
|
|
43
|
+
delete(key) {
|
|
44
|
+
entries.delete(key);
|
|
45
|
+
},
|
|
46
|
+
deleteByPrefix(prefix: string) {
|
|
47
|
+
for (const key of entries.keys()) {
|
|
48
|
+
if (typeof key === "string" && key.startsWith(prefix)) {
|
|
49
|
+
entries.delete(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
getOrCreate(key, factory) {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
pruneExpired(now);
|
|
56
|
+
|
|
57
|
+
const existing = entries.get(key);
|
|
58
|
+
if (existing) {
|
|
59
|
+
return existing.value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const value = (async () => {
|
|
63
|
+
try {
|
|
64
|
+
return await factory();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
entries.delete(key);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
|
|
71
|
+
entries.set(key, {
|
|
72
|
+
expiresAt: now + ttlMs,
|
|
73
|
+
value,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (entries.size > maxEntries) {
|
|
77
|
+
deleteOldest();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return value;
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createHighlighter } from "shiki";
|
|
2
|
+
|
|
3
|
+
const COMMON_LANGS = [
|
|
4
|
+
"bash",
|
|
5
|
+
"css",
|
|
6
|
+
"diff",
|
|
7
|
+
"go",
|
|
8
|
+
"graphql",
|
|
9
|
+
"html",
|
|
10
|
+
"javascript",
|
|
11
|
+
"json",
|
|
12
|
+
"jsx",
|
|
13
|
+
"markdown",
|
|
14
|
+
"mdx",
|
|
15
|
+
"python",
|
|
16
|
+
"rust",
|
|
17
|
+
"sql",
|
|
18
|
+
"tsx",
|
|
19
|
+
"typescript",
|
|
20
|
+
"yaml",
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
const THEMES = ["github-dark", "github-light"] as const;
|
|
24
|
+
|
|
25
|
+
let highlighterPromise: ReturnType<typeof createHighlighter> | null = null;
|
|
26
|
+
|
|
27
|
+
export const getHighlighter = () => {
|
|
28
|
+
if (!highlighterPromise) {
|
|
29
|
+
highlighterPromise = createHighlighter({
|
|
30
|
+
langs: [...COMMON_LANGS],
|
|
31
|
+
themes: [...THEMES],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return highlighterPromise;
|
|
35
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SiteConfig } from "@repo/models";
|
|
2
|
+
import type { CSSProperties } from "react";
|
|
3
|
+
|
|
4
|
+
export const themeStylesFromConfig = (config: SiteConfig): CSSProperties => {
|
|
5
|
+
const { colors } = config;
|
|
6
|
+
if (!colors) {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const styles: Record<string, string> = {};
|
|
11
|
+
|
|
12
|
+
if (colors.primary) {
|
|
13
|
+
styles["--color-primary"] = colors.primary;
|
|
14
|
+
}
|
|
15
|
+
if (colors.border) {
|
|
16
|
+
styles["--color-border"] = colors.border;
|
|
17
|
+
}
|
|
18
|
+
if (colors.muted) {
|
|
19
|
+
styles["--color-muted"] = colors.muted;
|
|
20
|
+
}
|
|
21
|
+
if (colors.surface) {
|
|
22
|
+
styles["--color-surface"] = colors.surface;
|
|
23
|
+
}
|
|
24
|
+
if (colors.background) {
|
|
25
|
+
styles["--color-background"] = colors.background;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return styles as CSSProperties;
|
|
29
|
+
};
|
package/docs/lib/toc.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blodemd",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Blode.md CLI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
"blodemd": "./dist/cli.mjs"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
|
-
"dist"
|
|
13
|
+
"dist",
|
|
14
|
+
"dev-server",
|
|
15
|
+
"docs",
|
|
16
|
+
"packages"
|
|
14
17
|
],
|
|
15
18
|
"type": "module",
|
|
16
19
|
"main": "./dist/index.mjs",
|
|
@@ -24,6 +27,7 @@
|
|
|
24
27
|
},
|
|
25
28
|
"scripts": {
|
|
26
29
|
"build": "tsdown",
|
|
30
|
+
"prepublishOnly": "node scripts/prepare-dist.mjs",
|
|
27
31
|
"check-types": "tsc --noEmit -p tsconfig.json",
|
|
28
32
|
"lint": "oxlint .",
|
|
29
33
|
"lint:fix": "oxlint --fix .",
|
|
@@ -31,12 +35,39 @@
|
|
|
31
35
|
"format:check": "oxfmt ."
|
|
32
36
|
},
|
|
33
37
|
"dependencies": {
|
|
38
|
+
"@base-ui/react": "^1.3.0",
|
|
34
39
|
"@clack/prompts": "^1.0.0",
|
|
40
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
41
|
+
"@shikijs/rehype": "^4.0.2",
|
|
42
|
+
"@tailwindcss/postcss": "^4.2.2",
|
|
43
|
+
"blode-icons-react": "^0.3.10",
|
|
35
44
|
"chalk": "^5.6.2",
|
|
45
|
+
"chokidar": "^4.0.3",
|
|
46
|
+
"class-variance-authority": "^0.7.1",
|
|
47
|
+
"clsx": "^2.1.1",
|
|
48
|
+
"cmdk": "^1.1.1",
|
|
36
49
|
"commander": "^14.0.0",
|
|
37
|
-
"
|
|
50
|
+
"geist": "^1.7.0",
|
|
51
|
+
"next": "16.2.1",
|
|
52
|
+
"next-mdx-remote": "^6.0.0",
|
|
53
|
+
"next-themes": "^0.4.6",
|
|
54
|
+
"open": "^10.2.0",
|
|
55
|
+
"radix-ui": "^1.4.3",
|
|
56
|
+
"react": "^19.2.0",
|
|
57
|
+
"react-dom": "^19.2.0",
|
|
58
|
+
"rehype-autolink-headings": "^7.1.0",
|
|
59
|
+
"rehype-slug": "^6.0.0",
|
|
60
|
+
"remark-gfm": "^4.0.0",
|
|
61
|
+
"shadcn": "^4.1.1",
|
|
62
|
+
"shiki": "^4.0.2",
|
|
63
|
+
"tailwind-merge": "^3.5.0",
|
|
64
|
+
"tailwindcss": "^4.2.2",
|
|
65
|
+
"tw-animate-css": "^1.4.0",
|
|
66
|
+
"yaml": "^2.8.3",
|
|
67
|
+
"zod": "^4.3.6"
|
|
38
68
|
},
|
|
39
69
|
"devDependencies": {
|
|
70
|
+
"@repo/previewing": "*",
|
|
40
71
|
"@repo/typescript-config": "*",
|
|
41
72
|
"@types/node": "^22.15.3",
|
|
42
73
|
"oxfmt": "^0.42.0",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const normalizePath: (value: string) => string;
|
|
2
|
+
export declare const withLeadingSlash: (value: string) => string;
|
|
3
|
+
export declare const withoutLeadingSlash: (value: string) => string;
|
|
4
|
+
export declare const slugify: (value: string) => string;
|
|
5
|
+
export declare const ensureArray: <T>(value?: T | T[]) => T[];
|
|
6
|
+
export declare const uniq: <T>(values: T[]) => T[];
|
|
7
|
+
export declare const safeJsonParse: <T>(value: string) => T | null;
|
|
8
|
+
export declare const clamp: (value: number, min: number, max: number) => number;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,WAK1C,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,WAK7C,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,WAKhD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,WAKL,CAAC;AAEjC,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,QAK7C,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAyB,CAAC;AAE7D,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,OAAO,MAAM,KAAG,CAAC,GAAG,IAMpD,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,WACxB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const BACKSLASH_TO_SLASH_REGEX = /\\/g;
|
|
2
|
+
const TRAILING_SLASHES_REGEX = /\/+$/g;
|
|
3
|
+
const LEADING_SLASHES_REGEX = /^\/+/;
|
|
4
|
+
export const normalizePath = (value) => {
|
|
5
|
+
const trimmed = value
|
|
6
|
+
.replace(BACKSLASH_TO_SLASH_REGEX, "/")
|
|
7
|
+
.replace(TRAILING_SLASHES_REGEX, "");
|
|
8
|
+
return trimmed.replace(LEADING_SLASHES_REGEX, "");
|
|
9
|
+
};
|
|
10
|
+
export const withLeadingSlash = (value) => {
|
|
11
|
+
if (!value) {
|
|
12
|
+
return "/";
|
|
13
|
+
}
|
|
14
|
+
return value.startsWith("/") ? value : `/${value}`;
|
|
15
|
+
};
|
|
16
|
+
export const withoutLeadingSlash = (value) => {
|
|
17
|
+
if (!value) {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
return value.startsWith("/") ? value.slice(1) : value;
|
|
21
|
+
};
|
|
22
|
+
export const slugify = (value) => value
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.trim()
|
|
25
|
+
.replaceAll(/[^a-z0-9]+/g, "-")
|
|
26
|
+
.replaceAll(/(^-|-$)+/g, "");
|
|
27
|
+
export const ensureArray = (value) => {
|
|
28
|
+
if (value === undefined) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return Array.isArray(value) ? value : [value];
|
|
32
|
+
};
|
|
33
|
+
export const uniq = (values) => [...new Set(values)];
|
|
34
|
+
export const safeJsonParse = (value) => {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(value);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@repo/common",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./src/index.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./*": {
|
|
13
|
+
"types": "./src/*.ts",
|
|
14
|
+
"import": "./dist/*.js",
|
|
15
|
+
"default": "./dist/*.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "rm -rf dist && tsc",
|
|
20
|
+
"check-types": "tsc --noEmit",
|
|
21
|
+
"lint": "oxlint .",
|
|
22
|
+
"lint:fix": "oxlint --fix .",
|
|
23
|
+
"format": "oxfmt --write .",
|
|
24
|
+
"format:check": "oxfmt ."
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@repo/typescript-config": "*",
|
|
28
|
+
"@types/node": "^22.19.15",
|
|
29
|
+
"oxfmt": "^0.42.0",
|
|
30
|
+
"oxlint": "^1.57.0",
|
|
31
|
+
"typescript": "6.0.2",
|
|
32
|
+
"ultracite": "^7.3.2"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
clamp,
|
|
5
|
+
ensureArray,
|
|
6
|
+
normalizePath,
|
|
7
|
+
safeJsonParse,
|
|
8
|
+
slugify,
|
|
9
|
+
uniq,
|
|
10
|
+
withLeadingSlash,
|
|
11
|
+
withoutLeadingSlash,
|
|
12
|
+
} from "./index";
|
|
13
|
+
|
|
14
|
+
describe("common utilities", () => {
|
|
15
|
+
it("normalizes paths", () => {
|
|
16
|
+
expect(normalizePath("/docs/guide/")).toBe("docs/guide");
|
|
17
|
+
expect(normalizePath("\\docs\\guide\\")).toBe("docs/guide");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("adds and removes leading slashes", () => {
|
|
21
|
+
expect(withLeadingSlash("docs")).toBe("/docs");
|
|
22
|
+
expect(withLeadingSlash("/docs")).toBe("/docs");
|
|
23
|
+
expect(withLeadingSlash("")).toBe("/");
|
|
24
|
+
expect(withoutLeadingSlash("/docs")).toBe("docs");
|
|
25
|
+
expect(withoutLeadingSlash("docs")).toBe("docs");
|
|
26
|
+
expect(withoutLeadingSlash("")).toBe("");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("slugifies strings", () => {
|
|
30
|
+
expect(slugify("Hello, blodemd!")).toBe("hello-blodemd");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("normalizes arrays", () => {
|
|
34
|
+
expect(ensureArray()).toEqual([]);
|
|
35
|
+
expect(ensureArray("one")).toEqual(["one"]);
|
|
36
|
+
expect(ensureArray(["one", "two"])).toEqual(["one", "two"]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("deduplicates arrays", () => {
|
|
40
|
+
expect(uniq(["a", "a", "b"])).toEqual(["a", "b"]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("safely parses JSON", () => {
|
|
44
|
+
expect(safeJsonParse<{ ok: boolean }>('{"ok":true}')).toEqual({
|
|
45
|
+
ok: true,
|
|
46
|
+
});
|
|
47
|
+
expect(safeJsonParse("{")).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("clamps values", () => {
|
|
51
|
+
expect(clamp(5, 0, 10)).toBe(5);
|
|
52
|
+
expect(clamp(-1, 0, 10)).toBe(0);
|
|
53
|
+
expect(clamp(11, 0, 10)).toBe(10);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const BACKSLASH_TO_SLASH_REGEX = /\\/g;
|
|
2
|
+
const TRAILING_SLASHES_REGEX = /\/+$/g;
|
|
3
|
+
const LEADING_SLASHES_REGEX = /^\/+/;
|
|
4
|
+
|
|
5
|
+
export const normalizePath = (value: string) => {
|
|
6
|
+
const trimmed = value
|
|
7
|
+
.replace(BACKSLASH_TO_SLASH_REGEX, "/")
|
|
8
|
+
.replace(TRAILING_SLASHES_REGEX, "");
|
|
9
|
+
return trimmed.replace(LEADING_SLASHES_REGEX, "");
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const withLeadingSlash = (value: string) => {
|
|
13
|
+
if (!value) {
|
|
14
|
+
return "/";
|
|
15
|
+
}
|
|
16
|
+
return value.startsWith("/") ? value : `/${value}`;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const withoutLeadingSlash = (value: string) => {
|
|
20
|
+
if (!value) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
return value.startsWith("/") ? value.slice(1) : value;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const slugify = (value: string) =>
|
|
27
|
+
value
|
|
28
|
+
.toLowerCase()
|
|
29
|
+
.trim()
|
|
30
|
+
.replaceAll(/[^a-z0-9]+/g, "-")
|
|
31
|
+
.replaceAll(/(^-|-$)+/g, "");
|
|
32
|
+
|
|
33
|
+
export const ensureArray = <T>(value?: T | T[]) => {
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
return [] as T[];
|
|
36
|
+
}
|
|
37
|
+
return Array.isArray(value) ? value : [value];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const uniq = <T>(values: T[]) => [...new Set(values)];
|
|
41
|
+
|
|
42
|
+
export const safeJsonParse = <T>(value: string): T | null => {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(value) as T;
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const clamp = (value: number, min: number, max: number) =>
|
|
51
|
+
Math.min(Math.max(value, min), max);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ApiKeySchema: z.ZodObject<{
|
|
3
|
+
createdAt: z.ZodString;
|
|
4
|
+
id: z.ZodString;
|
|
5
|
+
lastUsedAt: z.ZodOptional<z.ZodString>;
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
prefix: z.ZodString;
|
|
8
|
+
projectId: z.ZodString;
|
|
9
|
+
revokedAt: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type ApiKey = z.infer<typeof ApiKeySchema>;
|
|
12
|
+
export declare const ApiKeyCreateSchema: z.ZodObject<{
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
projectId: z.ZodString;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
export type ApiKeyCreateInput = z.infer<typeof ApiKeyCreateSchema>;
|
|
17
|
+
export declare const ApiKeyCreateResponseSchema: z.ZodObject<{
|
|
18
|
+
apiKey: z.ZodObject<{
|
|
19
|
+
createdAt: z.ZodString;
|
|
20
|
+
id: z.ZodString;
|
|
21
|
+
lastUsedAt: z.ZodOptional<z.ZodString>;
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
prefix: z.ZodString;
|
|
24
|
+
projectId: z.ZodString;
|
|
25
|
+
revokedAt: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
token: z.ZodString;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
export type ApiKeyCreateResponse = z.infer<typeof ApiKeyCreateResponseSchema>;
|
|
30
|
+
//# sourceMappingURL=api-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.d.ts","sourceRoot":"","sources":["../src/api-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,YAAY;;;;;;;;iBAQvB,CAAC;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEnE,eAAO,MAAM,0BAA0B;;;;;;;;;;;iBAGrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { IsoDateSchema } from "./dates.js";
|
|
3
|
+
import { IdSchema } from "./ids.js";
|
|
4
|
+
export const ApiKeySchema = z.object({
|
|
5
|
+
createdAt: IsoDateSchema,
|
|
6
|
+
id: IdSchema,
|
|
7
|
+
lastUsedAt: IsoDateSchema.optional(),
|
|
8
|
+
name: z.string().min(1),
|
|
9
|
+
prefix: z.string().min(1),
|
|
10
|
+
projectId: IdSchema,
|
|
11
|
+
revokedAt: IsoDateSchema.optional(),
|
|
12
|
+
});
|
|
13
|
+
export const ApiKeyCreateSchema = z.object({
|
|
14
|
+
name: z.string().min(1),
|
|
15
|
+
projectId: IdSchema,
|
|
16
|
+
});
|
|
17
|
+
export const ApiKeyCreateResponseSchema = z.object({
|
|
18
|
+
apiKey: ApiKeySchema,
|
|
19
|
+
token: z.string().min(1),
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,aAAwB,CAAC;AACnD,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
|