@heyo-sh/create-heyo-docs 0.1.0
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 +21 -0
- package/deployments/cloudflare/astro/package.json +12 -0
- package/deployments/cloudflare/astro/platform.astro.ts +4 -0
- package/deployments/cloudflare/astro/wrangler.jsonc +6 -0
- package/deployments/cloudflare/next/open-next.config.ts +3 -0
- package/deployments/cloudflare/next/package.json +13 -0
- package/deployments/cloudflare/next/wrangler.jsonc +11 -0
- package/deployments/cloudflare/react-router/app/entry.server.tsx +48 -0
- package/deployments/cloudflare/react-router/package.json +21 -0
- package/deployments/cloudflare/react-router/platform.vite.ts +6 -0
- package/deployments/cloudflare/react-router/react-router.config.ts +20 -0
- package/deployments/cloudflare/react-router/workers/app.ts +12 -0
- package/deployments/cloudflare/react-router/wrangler.jsonc +10 -0
- package/deployments/vercel/astro/package.json +11 -0
- package/deployments/vercel/astro/platform.astro.ts +4 -0
- package/deployments/vercel/astro/vercel.json +4 -0
- package/deployments/vercel/next/package.json +8 -0
- package/deployments/vercel/next/vercel.json +3 -0
- package/deployments/vercel/react-router/package.json +12 -0
- package/deployments/vercel/react-router/platform.vite.ts +4 -0
- package/deployments/vercel/react-router/react-router.config.ts +22 -0
- package/deployments/vercel/react-router/vercel.json +4 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +328 -0
- package/dist/package-manager.d.ts +6 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/project-name.d.ts +3 -0
- package/dist/project-name.d.ts.map +1 -0
- package/dist/scaffold.d.ts +5 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +36 -0
- package/templates/astro/astro.config.ts +15 -0
- package/templates/astro/components.json +25 -0
- package/templates/astro/content/getting-started.mdx +16 -0
- package/templates/astro/content/index.mdx +22 -0
- package/templates/astro/content/mdx-components.mdx +44 -0
- package/templates/astro/heyo-docs.config.ts +24 -0
- package/templates/astro/package.json +34 -0
- package/templates/astro/platform.astro.ts +4 -0
- package/templates/astro/public/apple-touch-icon.png +0 -0
- package/templates/astro/public/favicon-96x96.png +0 -0
- package/templates/astro/public/favicon.ico +0 -0
- package/templates/astro/public/favicon.svg +1 -0
- package/templates/astro/public/logo.svg +12 -0
- package/templates/astro/public/site.webmanifest +21 -0
- package/templates/astro/public/web-app-manifest-192x192.png +0 -0
- package/templates/astro/public/web-app-manifest-512x512.png +0 -0
- package/templates/astro/src/components/docs-app.tsx +165 -0
- package/templates/astro/src/components/theme-provider.tsx +106 -0
- package/templates/astro/src/env.d.ts +2 -0
- package/templates/astro/src/heyo-docs-icons.tsx +79 -0
- package/templates/astro/src/layouts/docs-layout.astro +70 -0
- package/templates/astro/src/lib/docs.ts +31 -0
- package/templates/astro/src/lib/openapi-request.ts +160 -0
- package/templates/astro/src/lib/seo.ts +221 -0
- package/templates/astro/src/lib/theme.ts +74 -0
- package/templates/astro/src/pages/[...slug].astro +50 -0
- package/templates/astro/src/pages/[...slug].md.ts +28 -0
- package/templates/astro/src/pages/heyo-docs-internal/openapi-request.ts +8 -0
- package/templates/astro/src/pages/llms-full.txt.ts +13 -0
- package/templates/astro/src/pages/llms.txt.ts +13 -0
- package/templates/astro/src/pages/robots.txt.ts +19 -0
- package/templates/astro/src/pages/rss.xml.ts +13 -0
- package/templates/astro/src/pages/sitemap.xml.ts +19 -0
- package/templates/astro/src/styles/app.css +8 -0
- package/templates/astro/src/virtual.d.ts +19 -0
- package/templates/astro/tsconfig.json +12 -0
- package/templates/next/app/[[...slug]]/page.tsx +59 -0
- package/templates/next/app/app.css +8 -0
- package/templates/next/app/components/docs-app.tsx +139 -0
- package/templates/next/app/components/theme-provider.tsx +93 -0
- package/templates/next/app/error.tsx +8 -0
- package/templates/next/app/heyo-docs-icons.tsx +70 -0
- package/templates/next/app/heyo-docs-internal/markdown/[[...slug]]/route.ts +26 -0
- package/templates/next/app/heyo-docs-internal/openapi-request/route.ts +5 -0
- package/templates/next/app/layout.tsx +79 -0
- package/templates/next/app/lib/docs.ts +43 -0
- package/templates/next/app/lib/openapi-request.ts +147 -0
- package/templates/next/app/lib/seo.ts +189 -0
- package/templates/next/app/lib/theme.ts +61 -0
- package/templates/next/app/llms-full.txt/route.ts +10 -0
- package/templates/next/app/llms.txt/route.ts +10 -0
- package/templates/next/app/not-found.tsx +13 -0
- package/templates/next/app/robots.txt/route.ts +16 -0
- package/templates/next/app/rss.xml/route.ts +10 -0
- package/templates/next/app/sitemap.xml/route.ts +14 -0
- package/templates/next/components.json +20 -0
- package/templates/next/content/getting-started.mdx +16 -0
- package/templates/next/content/index.mdx +22 -0
- package/templates/next/content/mdx-components.mdx +41 -0
- package/templates/next/heyo-docs.config.ts +24 -0
- package/templates/next/mdx.d.ts +6 -0
- package/templates/next/next-env.d.ts +7 -0
- package/templates/next/next.config.ts +23 -0
- package/templates/next/package.json +40 -0
- package/templates/next/postcss.config.mjs +5 -0
- package/templates/next/public/apple-touch-icon.png +0 -0
- package/templates/next/public/favicon-96x96.png +0 -0
- package/templates/next/public/favicon.ico +0 -0
- package/templates/next/public/favicon.svg +1 -0
- package/templates/next/public/logo.svg +12 -0
- package/templates/next/public/site.webmanifest +21 -0
- package/templates/next/public/web-app-manifest-192x192.png +0 -0
- package/templates/next/public/web-app-manifest-512x512.png +0 -0
- package/templates/next/scripts/generate-heyo-docs.ts +50 -0
- package/templates/next/tsconfig.json +27 -0
- package/templates/react-router/app/app.css +8 -0
- package/templates/react-router/app/components/theme-provider.tsx +106 -0
- package/templates/react-router/app/heyo-docs-icons.tsx +71 -0
- package/templates/react-router/app/lib/theme.ts +74 -0
- package/templates/react-router/app/root.tsx +140 -0
- package/templates/react-router/app/routes/docs.tsx +179 -0
- package/templates/react-router/app/routes/home.tsx +1 -0
- package/templates/react-router/app/routes/llms-full.ts +13 -0
- package/templates/react-router/app/routes/llms.ts +13 -0
- package/templates/react-router/app/routes/markdown.ts +25 -0
- package/templates/react-router/app/routes/openapi-request.ts +159 -0
- package/templates/react-router/app/routes/page.tsx +1 -0
- package/templates/react-router/app/routes/robots.ts +19 -0
- package/templates/react-router/app/routes/rss.ts +13 -0
- package/templates/react-router/app/routes/sitemap.ts +18 -0
- package/templates/react-router/app/routes.ts +13 -0
- package/templates/react-router/app/virtual.d.ts +19 -0
- package/templates/react-router/components.json +25 -0
- package/templates/react-router/content/getting-started.mdx +16 -0
- package/templates/react-router/content/index.mdx +22 -0
- package/templates/react-router/content/mdx-components.mdx +293 -0
- package/templates/react-router/heyo-docs.config.ts +24 -0
- package/templates/react-router/package.json +36 -0
- package/templates/react-router/platform.vite.ts +2 -0
- package/templates/react-router/public/apple-touch-icon.png +0 -0
- package/templates/react-router/public/favicon-96x96.png +0 -0
- package/templates/react-router/public/favicon.ico +0 -0
- package/templates/react-router/public/favicon.svg +1 -0
- package/templates/react-router/public/logo.svg +12 -0
- package/templates/react-router/public/site.webmanifest +21 -0
- package/templates/react-router/public/web-app-manifest-192x192.png +0 -0
- package/templates/react-router/public/web-app-manifest-512x512.png +0 -0
- package/templates/react-router/react-router.config.ts +20 -0
- package/templates/react-router/tsconfig.json +20 -0
- package/templates/react-router/vite.config.ts +17 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Heyo.sh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"deploy": "wrangler deploy --config dist/server/wrangler.json",
|
|
4
|
+
"cf-typegen": "wrangler types --config dist/server/wrangler.json"
|
|
5
|
+
},
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@astrojs/cloudflare": "^14.2.3"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"wrangler": "^4.125.0"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
|
|
4
|
+
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
|
|
5
|
+
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
|
|
6
|
+
},
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@opennextjs/cloudflare": "^1.20.2"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"wrangler": "^4.125.0"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/wrangler/config-schema.json",
|
|
3
|
+
"name": "{{PROJECT_NAME}}",
|
|
4
|
+
"main": ".open-next/worker.js",
|
|
5
|
+
"compatibility_date": "2026-08-24",
|
|
6
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
7
|
+
"assets": {
|
|
8
|
+
"directory": ".open-next/assets",
|
|
9
|
+
"binding": "ASSETS",
|
|
10
|
+
},
|
|
11
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { EntryContext, RouterContextProvider } from "react-router";
|
|
2
|
+
import { ServerRouter } from "react-router";
|
|
3
|
+
import { isbot } from "isbot";
|
|
4
|
+
import { renderToReadableStream } from "react-dom/server";
|
|
5
|
+
|
|
6
|
+
export const streamTimeout = 5_000;
|
|
7
|
+
|
|
8
|
+
/** Web Streams entry required by Cloudflare Workers and build prerendering. */
|
|
9
|
+
export default async function handleRequest(
|
|
10
|
+
request: Request,
|
|
11
|
+
responseStatusCode: number,
|
|
12
|
+
responseHeaders: Headers,
|
|
13
|
+
routerContext: EntryContext,
|
|
14
|
+
_loadContext: RouterContextProvider,
|
|
15
|
+
) {
|
|
16
|
+
if (request.method.toUpperCase() === "HEAD") {
|
|
17
|
+
return new Response(null, {
|
|
18
|
+
status: responseStatusCode,
|
|
19
|
+
headers: responseHeaders,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let shellRendered = false;
|
|
24
|
+
const body = await renderToReadableStream(
|
|
25
|
+
<ServerRouter context={routerContext} url={request.url} />,
|
|
26
|
+
{
|
|
27
|
+
signal: AbortSignal.timeout(streamTimeout + 1_000),
|
|
28
|
+
onError(error: unknown) {
|
|
29
|
+
responseStatusCode = 500;
|
|
30
|
+
if (shellRendered) console.error(error);
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
shellRendered = true;
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
(request.headers.get("user-agent") &&
|
|
38
|
+
isbot(request.headers.get("user-agent")!)) ||
|
|
39
|
+
routerContext.isSpaMode
|
|
40
|
+
)
|
|
41
|
+
await body.allReady;
|
|
42
|
+
|
|
43
|
+
responseHeaders.set("Content-Type", "text/html");
|
|
44
|
+
return new Response(body, {
|
|
45
|
+
headers: responseHeaders,
|
|
46
|
+
status: responseStatusCode,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"@react-router/node": "8.3.0",
|
|
4
|
+
"react-router": "8.3.0"
|
|
5
|
+
},
|
|
6
|
+
"scripts": {
|
|
7
|
+
"deploy": "wrangler deploy",
|
|
8
|
+
"cf-typegen": "wrangler types"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@react-router/dev": "8.3.0",
|
|
12
|
+
"@react-router/serve": "8.3.0",
|
|
13
|
+
"@cloudflare/vite-plugin": "1.53.1",
|
|
14
|
+
"@types/node": "26.2.0",
|
|
15
|
+
"@types/react": "19.2.18",
|
|
16
|
+
"@types/react-dom": "19.2.4",
|
|
17
|
+
"typescript": "7.0.2",
|
|
18
|
+
"vite": "8.2.2",
|
|
19
|
+
"wrangler": "4.125.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Config } from "@react-router/dev/config";
|
|
2
|
+
import { documentationPaths } from "@heyo-sh/heyo-docs/node";
|
|
3
|
+
|
|
4
|
+
import config from "./heyo-docs.config";
|
|
5
|
+
|
|
6
|
+
/** Cloudflare serves prebuilt docs; the Worker is reserved for request actions. */
|
|
7
|
+
export default {
|
|
8
|
+
ssr: true,
|
|
9
|
+
async prerender() {
|
|
10
|
+
const docs = await documentationPaths(process.cwd(), config);
|
|
11
|
+
return [
|
|
12
|
+
...docs,
|
|
13
|
+
"/robots.txt",
|
|
14
|
+
"/sitemap.xml",
|
|
15
|
+
"/rss.xml",
|
|
16
|
+
"/llms.txt",
|
|
17
|
+
"/llms-full.txt",
|
|
18
|
+
];
|
|
19
|
+
},
|
|
20
|
+
} satisfies Config;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createRequestHandler, RouterContextProvider } from "react-router";
|
|
2
|
+
|
|
3
|
+
const handleRequest = createRequestHandler(
|
|
4
|
+
() => import("virtual:react-router/server-build"),
|
|
5
|
+
import.meta.env.MODE,
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
fetch(request) {
|
|
10
|
+
return handleRequest(request, new RouterContextProvider());
|
|
11
|
+
},
|
|
12
|
+
} satisfies ExportedHandler<Env>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Config } from "@react-router/dev/config";
|
|
2
|
+
import { vercelPreset } from "@vercel/react-router/vite";
|
|
3
|
+
import { documentationPaths } from "@heyo-sh/heyo-docs/node";
|
|
4
|
+
|
|
5
|
+
import config from "./heyo-docs.config";
|
|
6
|
+
|
|
7
|
+
/** Vercel serves prebuilt docs; Functions are reserved for request actions. */
|
|
8
|
+
export default {
|
|
9
|
+
ssr: true,
|
|
10
|
+
presets: [vercelPreset()],
|
|
11
|
+
async prerender() {
|
|
12
|
+
const docs = await documentationPaths(process.cwd(), config);
|
|
13
|
+
return [
|
|
14
|
+
...docs,
|
|
15
|
+
"/robots.txt",
|
|
16
|
+
"/sitemap.xml",
|
|
17
|
+
"/rss.xml",
|
|
18
|
+
"/llms.txt",
|
|
19
|
+
"/llms-full.txt",
|
|
20
|
+
];
|
|
21
|
+
},
|
|
22
|
+
} satisfies Config;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import type { CreateOptions } from "./types";
|
|
3
|
+
export { detectPackageManager, packageManagerField, packageManagerRunCommand, } from "./package-manager";
|
|
4
|
+
export { scaffoldProject } from "./scaffold";
|
|
5
|
+
export { mergePackageJson, replacePlaceholders } from "./utils";
|
|
6
|
+
export type * from "./types";
|
|
7
|
+
export declare function run(argv?: string[]): Promise<void>;
|
|
8
|
+
export declare function parseArguments(argv: string[]): {
|
|
9
|
+
options: CreateOptions;
|
|
10
|
+
interactive: boolean;
|
|
11
|
+
showHelp: boolean;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAChE,mBAAmB,SAAS,CAAC;AA2C7B,wBAAsB,GAAG,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAC9C,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAsDA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
import * as p from "@clack/prompts";
|
|
6
|
+
|
|
7
|
+
// src/package-manager.ts
|
|
8
|
+
var FALLBACK_VERSIONS = {
|
|
9
|
+
bun: "1.3.1",
|
|
10
|
+
pnpm: "10.17.0",
|
|
11
|
+
npm: "11.6.0",
|
|
12
|
+
yarn: "4.9.4"
|
|
13
|
+
};
|
|
14
|
+
function detectPackageManager(userAgent = process.env.npm_config_user_agent ?? "") {
|
|
15
|
+
const match = userAgent.match(/(?:^|\s)(bun|pnpm|npm|yarn)\/([^\s]+)/);
|
|
16
|
+
if (!match)
|
|
17
|
+
return { name: "bun", version: Bun.version };
|
|
18
|
+
return { name: match[1], version: match[2] };
|
|
19
|
+
}
|
|
20
|
+
function packageManagerField(manager, detected = detectPackageManager()) {
|
|
21
|
+
if (manager === detected.name && detected.version)
|
|
22
|
+
return `${manager}@${detected.version}`;
|
|
23
|
+
const executable = manager === "yarn" ? "yarn" : manager;
|
|
24
|
+
try {
|
|
25
|
+
const result = Bun.spawnSync([executable, "--version"]);
|
|
26
|
+
const version = new TextDecoder().decode(result.stdout).trim();
|
|
27
|
+
if (result.exitCode === 0 && /^\d+(?:\.\d+)+/.test(version))
|
|
28
|
+
return `${manager}@${version}`;
|
|
29
|
+
} catch {}
|
|
30
|
+
return `${manager}@${FALLBACK_VERSIONS[manager]}`;
|
|
31
|
+
}
|
|
32
|
+
function packageManagerInstallCommand(manager) {
|
|
33
|
+
return manager === "yarn" ? ["yarn"] : [manager, "install"];
|
|
34
|
+
}
|
|
35
|
+
function packageManagerRunCommand(manager, script) {
|
|
36
|
+
if (manager === "npm")
|
|
37
|
+
return `npm run ${script}`;
|
|
38
|
+
if (manager === "yarn")
|
|
39
|
+
return `yarn ${script}`;
|
|
40
|
+
return `${manager} run ${script}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/project-name.ts
|
|
44
|
+
var PROJECT_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/i;
|
|
45
|
+
function projectNameError(value) {
|
|
46
|
+
if (!value.trim())
|
|
47
|
+
return "Enter a project name.";
|
|
48
|
+
if (!PROJECT_NAME_PATTERN.test(value))
|
|
49
|
+
return "Use letters, numbers and hyphens only.";
|
|
50
|
+
}
|
|
51
|
+
function assertProjectName(value) {
|
|
52
|
+
const error = projectNameError(value);
|
|
53
|
+
if (error)
|
|
54
|
+
throw new Error(error);
|
|
55
|
+
return value.trim();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/scaffold.ts
|
|
59
|
+
import { existsSync } from "fs";
|
|
60
|
+
import { mkdir as mkdir2, readdir as readdir2 } from "fs/promises";
|
|
61
|
+
import { join as join2, resolve } from "path";
|
|
62
|
+
|
|
63
|
+
// src/utils.ts
|
|
64
|
+
import {
|
|
65
|
+
cp,
|
|
66
|
+
mkdir,
|
|
67
|
+
readFile,
|
|
68
|
+
readdir,
|
|
69
|
+
rm,
|
|
70
|
+
stat,
|
|
71
|
+
writeFile
|
|
72
|
+
} from "fs/promises";
|
|
73
|
+
import { dirname, join } from "path";
|
|
74
|
+
function replacePlaceholders(source, values) {
|
|
75
|
+
return source.replace(/\{\{([A-Z0-9_]+)\}\}/g, (placeholder, key) => values[key] ?? placeholder);
|
|
76
|
+
}
|
|
77
|
+
function mergePackageJson(base, overlay) {
|
|
78
|
+
const merged = { ...base };
|
|
79
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
80
|
+
const current = merged[key];
|
|
81
|
+
if (isRecord(current) && isRecord(value))
|
|
82
|
+
merged[key] = mergePackageJson(current, value);
|
|
83
|
+
else
|
|
84
|
+
merged[key] = value;
|
|
85
|
+
}
|
|
86
|
+
return merged;
|
|
87
|
+
}
|
|
88
|
+
async function copyTemplate(source, destination, placeholders) {
|
|
89
|
+
await cp(source, destination, { recursive: true, force: true });
|
|
90
|
+
await replacePlaceholdersAtPath(destination, placeholders);
|
|
91
|
+
}
|
|
92
|
+
async function replacePlaceholdersAtPath(path, values) {
|
|
93
|
+
if (!(await stat(path)).isDirectory()) {
|
|
94
|
+
const contents = await readFile(path, "utf8");
|
|
95
|
+
await writeFile(path, replacePlaceholders(contents, values));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const entries = await readdir(path, { withFileTypes: true });
|
|
99
|
+
await Promise.all(entries.map((entry) => replacePlaceholdersAtPath(join(path, entry.name), values)));
|
|
100
|
+
}
|
|
101
|
+
async function writeJson(path, data) {
|
|
102
|
+
await mkdir(dirname(path), { recursive: true });
|
|
103
|
+
await writeFile(path, `${JSON.stringify(data, null, 2)}
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
async function readJson(path) {
|
|
107
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
108
|
+
}
|
|
109
|
+
function isRecord(value) {
|
|
110
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/scaffold.ts
|
|
114
|
+
var packageRoot = resolve(import.meta.dirname, "..");
|
|
115
|
+
async function scaffoldProject(options) {
|
|
116
|
+
const cwd = options.cwd ?? process.cwd();
|
|
117
|
+
const projectName = assertProjectName(options.projectName);
|
|
118
|
+
const projectPath = resolve(cwd, projectName);
|
|
119
|
+
if (existsSync(projectPath))
|
|
120
|
+
throw new Error(`Directory already exists: ${projectPath}`);
|
|
121
|
+
const placeholders = {
|
|
122
|
+
PROJECT_NAME: projectName,
|
|
123
|
+
HEYO_DOCS_VERSION: options.heyoDocsVersion ?? "0.1.0",
|
|
124
|
+
PACKAGE_MANAGER: packageManagerField(options.packageManager),
|
|
125
|
+
THEME: options.theme
|
|
126
|
+
};
|
|
127
|
+
const templatePath = join2(packageRoot, "templates", options.template);
|
|
128
|
+
const deploymentPath = join2(packageRoot, "deployments", options.deployment, options.template);
|
|
129
|
+
await mkdir2(projectPath, { recursive: true });
|
|
130
|
+
await copyTemplate(templatePath, projectPath, placeholders);
|
|
131
|
+
const basePackage = await readJson(join2(projectPath, "package.json"));
|
|
132
|
+
const overlayPackage = options.deployment === "later" ? {} : await readJson(join2(deploymentPath, "package.json"));
|
|
133
|
+
if (options.deployment !== "later") {
|
|
134
|
+
await copyOverlay(deploymentPath, projectPath, placeholders);
|
|
135
|
+
}
|
|
136
|
+
await writeJson(join2(projectPath, "package.json"), mergePackageJson(basePackage, overlayPackage));
|
|
137
|
+
if (options.install)
|
|
138
|
+
await installDependencies(projectPath, options.packageManager);
|
|
139
|
+
return { projectPath };
|
|
140
|
+
}
|
|
141
|
+
async function copyOverlay(source, destination, placeholders) {
|
|
142
|
+
const entries = await readdir2(source, { withFileTypes: true });
|
|
143
|
+
await Promise.all(entries.filter((entry) => entry.name !== "package.json").map(async (entry) => {
|
|
144
|
+
const sourcePath = join2(source, entry.name);
|
|
145
|
+
const destinationPath = join2(destination, entry.name);
|
|
146
|
+
return copyTemplate(sourcePath, destinationPath, placeholders);
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
async function installDependencies(projectPath, packageManager) {
|
|
150
|
+
const command = packageManagerInstallCommand(packageManager);
|
|
151
|
+
const process2 = Bun.spawn(command, {
|
|
152
|
+
cwd: projectPath,
|
|
153
|
+
stdout: "inherit",
|
|
154
|
+
stderr: "inherit"
|
|
155
|
+
});
|
|
156
|
+
if (await process2.exited !== 0)
|
|
157
|
+
throw new Error(`Dependency installation failed with ${command.join(" ")}.`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/index.ts
|
|
161
|
+
var USAGE = "Usage: create-heyo-docs [project-name] [--template react-router|next|astro] [--deployment cloudflare|vercel|later] [--theme grain|shade|moss] [--package-manager bun|pnpm|npm|yarn] [--no-install]";
|
|
162
|
+
var TEMPLATE_OPTIONS = [
|
|
163
|
+
{ value: "react-router", label: "React Router" },
|
|
164
|
+
{ value: "next", label: "Next.js" },
|
|
165
|
+
{ value: "astro", label: "Astro" }
|
|
166
|
+
];
|
|
167
|
+
var DEPLOYMENT_OPTIONS = [
|
|
168
|
+
{ value: "cloudflare", label: "Cloudflare" },
|
|
169
|
+
{ value: "vercel", label: "Vercel" },
|
|
170
|
+
{ value: "later", label: "Configure later" }
|
|
171
|
+
];
|
|
172
|
+
var THEME_OPTIONS = [
|
|
173
|
+
{ value: "grain", label: "Grain" },
|
|
174
|
+
{ value: "shade", label: "Shade" },
|
|
175
|
+
{ value: "moss", label: "Moss" },
|
|
176
|
+
{
|
|
177
|
+
value: "dripper",
|
|
178
|
+
label: "Dripper \u2014 Soon",
|
|
179
|
+
hint: "Unavailable in this MVP"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
value: "fixed-gear",
|
|
183
|
+
label: "Fixed Gear \u2014 Soon",
|
|
184
|
+
hint: "Unavailable in this MVP"
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
var PACKAGE_MANAGER_OPTIONS = [
|
|
188
|
+
{ value: "bun", label: "bun" },
|
|
189
|
+
{ value: "pnpm", label: "pnpm" },
|
|
190
|
+
{ value: "npm", label: "npm" },
|
|
191
|
+
{ value: "yarn", label: "yarn" }
|
|
192
|
+
];
|
|
193
|
+
if (import.meta.main) {
|
|
194
|
+
run(process.argv.slice(2)).catch((error) => {
|
|
195
|
+
p.log.error(error instanceof Error ? error.message : String(error));
|
|
196
|
+
process.exitCode = 1;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
async function run(argv = process.argv.slice(2)) {
|
|
200
|
+
const parsed = parseArguments(argv);
|
|
201
|
+
if (parsed.showHelp) {
|
|
202
|
+
p.note(USAGE, "@heyo-sh/create-heyo-docs");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const options = parsed.interactive ? await askQuestions(parsed.options) : parsed.options;
|
|
206
|
+
const spinner2 = p.spinner();
|
|
207
|
+
spinner2.start("Creating your Heyo Docs project");
|
|
208
|
+
try {
|
|
209
|
+
await scaffoldProject(options);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
spinner2.stop("Unable to create your documentation project");
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
spinner2.stop("Your documentation project is ready");
|
|
215
|
+
const install = options.install ? "" : `
|
|
216
|
+
${options.packageManager} install`;
|
|
217
|
+
p.note(`cd ${options.projectName}${install}
|
|
218
|
+
${packageManagerRunCommand(options.packageManager, "dev")}`, "Next steps");
|
|
219
|
+
p.outro("Happy documenting.");
|
|
220
|
+
}
|
|
221
|
+
function parseArguments(argv) {
|
|
222
|
+
const detected = detectPackageManager();
|
|
223
|
+
const options = {
|
|
224
|
+
projectName: "",
|
|
225
|
+
template: "react-router",
|
|
226
|
+
deployment: "later",
|
|
227
|
+
theme: "grain",
|
|
228
|
+
packageManager: detected.name,
|
|
229
|
+
install: true
|
|
230
|
+
};
|
|
231
|
+
let explicit = false;
|
|
232
|
+
let showHelp = false;
|
|
233
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
234
|
+
const value = argv[index];
|
|
235
|
+
if (!value.startsWith("-")) {
|
|
236
|
+
options.projectName ||= value;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
explicit = true;
|
|
240
|
+
if (value === "--template") {
|
|
241
|
+
options.template = readEnum(argv[++index], ["react-router", "next", "astro"], "template");
|
|
242
|
+
} else if (value === "--deployment") {
|
|
243
|
+
options.deployment = readEnum(argv[++index], ["cloudflare", "vercel", "later"], "deployment");
|
|
244
|
+
} else if (value === "--theme") {
|
|
245
|
+
options.theme = readEnum(argv[++index], ["grain", "shade", "moss"], "theme");
|
|
246
|
+
} else if (value === "--package-manager") {
|
|
247
|
+
options.packageManager = readEnum(argv[++index], ["bun", "pnpm", "npm", "yarn"], "package manager");
|
|
248
|
+
} else if (value === "--no-install") {
|
|
249
|
+
options.install = false;
|
|
250
|
+
} else if (value === "--install") {
|
|
251
|
+
options.install = true;
|
|
252
|
+
} else if (value === "--help" || value === "-h") {
|
|
253
|
+
showHelp = true;
|
|
254
|
+
} else {
|
|
255
|
+
throw new Error(`Unknown option: ${value}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return { options, interactive: !explicit && !options.projectName, showHelp };
|
|
259
|
+
}
|
|
260
|
+
async function askQuestions(defaults) {
|
|
261
|
+
p.intro("Create Heyo Docs");
|
|
262
|
+
const projectName = await p.text({
|
|
263
|
+
message: "Project name",
|
|
264
|
+
placeholder: "my-docs",
|
|
265
|
+
defaultValue: "my-docs",
|
|
266
|
+
validate: projectNameError
|
|
267
|
+
});
|
|
268
|
+
if (p.isCancel(projectName))
|
|
269
|
+
cancelCreation();
|
|
270
|
+
const template = await selectAvailable("Template", TEMPLATE_OPTIONS, [
|
|
271
|
+
"react-router",
|
|
272
|
+
"next",
|
|
273
|
+
"astro"
|
|
274
|
+
]);
|
|
275
|
+
const deployment = await selectAvailable("Deployment", DEPLOYMENT_OPTIONS, ["cloudflare", "vercel", "later"], defaults.deployment);
|
|
276
|
+
const theme = await selectAvailable("Theme", THEME_OPTIONS, [
|
|
277
|
+
"grain",
|
|
278
|
+
"shade",
|
|
279
|
+
"moss"
|
|
280
|
+
]);
|
|
281
|
+
const packageManager = await selectAvailable("Package manager", PACKAGE_MANAGER_OPTIONS, ["bun", "pnpm", "npm", "yarn"], defaults.packageManager);
|
|
282
|
+
const install = await p.confirm({
|
|
283
|
+
message: "Install dependencies?",
|
|
284
|
+
initialValue: true
|
|
285
|
+
});
|
|
286
|
+
if (p.isCancel(install))
|
|
287
|
+
cancelCreation();
|
|
288
|
+
return {
|
|
289
|
+
projectName,
|
|
290
|
+
template,
|
|
291
|
+
deployment,
|
|
292
|
+
theme,
|
|
293
|
+
packageManager,
|
|
294
|
+
install
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
async function selectAvailable(message, options, available, initialValue) {
|
|
298
|
+
for (;; ) {
|
|
299
|
+
const answer = await p.select({ message, options, initialValue });
|
|
300
|
+
if (p.isCancel(answer))
|
|
301
|
+
cancelCreation();
|
|
302
|
+
if (isOneOf(answer, available))
|
|
303
|
+
return answer;
|
|
304
|
+
p.log.warn("That option is planned but not available in this MVP.");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function isOneOf(value, values) {
|
|
308
|
+
return values.some((candidate) => candidate === value);
|
|
309
|
+
}
|
|
310
|
+
function cancelCreation() {
|
|
311
|
+
p.cancel("Creation cancelled.");
|
|
312
|
+
process.exit(0);
|
|
313
|
+
}
|
|
314
|
+
function readEnum(value, allowed, label) {
|
|
315
|
+
if (value && isOneOf(value, allowed))
|
|
316
|
+
return value;
|
|
317
|
+
throw new Error(`Use one of ${allowed.join(", ")} for ${label}.`);
|
|
318
|
+
}
|
|
319
|
+
export {
|
|
320
|
+
scaffoldProject,
|
|
321
|
+
run,
|
|
322
|
+
replacePlaceholders,
|
|
323
|
+
parseArguments,
|
|
324
|
+
packageManagerRunCommand,
|
|
325
|
+
packageManagerField,
|
|
326
|
+
mergePackageJson,
|
|
327
|
+
detectPackageManager
|
|
328
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DetectedPackageManager, PackageManager } from "./types";
|
|
2
|
+
export declare function detectPackageManager(userAgent?: string): DetectedPackageManager;
|
|
3
|
+
export declare function packageManagerField(manager: PackageManager, detected?: DetectedPackageManager): string;
|
|
4
|
+
export declare function packageManagerInstallCommand(manager: PackageManager): string[];
|
|
5
|
+
export declare function packageManagerRunCommand(manager: PackageManager, script: string): string;
|
|
6
|
+
//# sourceMappingURL=package-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../src/package-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAStE,wBAAgB,oBAAoB,CAClC,SAAS,SAA0C,GAClD,sBAAsB,CAIxB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EACvB,QAAQ,yBAAyB,GAChC,MAAM,CAaR;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,cAAc,GACtB,MAAM,EAAE,CAEV;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb,MAAM,CAIR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-name.d.ts","sourceRoot":"","sources":["../src/project-name.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIlE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD"}
|