@heyo-sh/create-heyo-docs 0.1.1 → 0.2.1
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 +44 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +349 -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 +5 -2
- package/templates/astro/content/configuration.mdx +76 -0
- package/templates/astro/content/deploying.mdx +57 -0
- package/templates/astro/content/essentials/callouts.mdx +36 -0
- package/templates/astro/content/essentials/code-blocks.mdx +51 -0
- package/templates/astro/content/essentials/lists.mdx +40 -0
- package/templates/astro/content/essentials/tables.mdx +37 -0
- package/templates/astro/content/essentials/tabs.mdx +42 -0
- package/templates/astro/content/essentials/text-styling.mdx +50 -0
- package/templates/astro/content/quickstart.mdx +60 -0
- package/templates/astro/heyo-docs.config.ts +24 -2
- package/templates/next/content/configuration.mdx +76 -0
- package/templates/next/content/deploying.mdx +57 -0
- package/templates/next/content/essentials/callouts.mdx +36 -0
- package/templates/next/content/essentials/code-blocks.mdx +51 -0
- package/templates/next/content/essentials/lists.mdx +40 -0
- package/templates/next/content/essentials/tables.mdx +37 -0
- package/templates/next/content/essentials/tabs.mdx +42 -0
- package/templates/next/content/essentials/text-styling.mdx +50 -0
- package/templates/next/content/quickstart.mdx +60 -0
- package/templates/next/heyo-docs.config.ts +24 -2
- package/templates/react-router/content/configuration.mdx +76 -0
- package/templates/react-router/content/deploying.mdx +57 -0
- package/templates/react-router/content/essentials/callouts.mdx +36 -0
- package/templates/react-router/content/essentials/code-blocks.mdx +51 -0
- package/templates/react-router/content/essentials/lists.mdx +40 -0
- package/templates/react-router/content/essentials/tables.mdx +37 -0
- package/templates/react-router/content/essentials/tabs.mdx +42 -0
- package/templates/react-router/content/essentials/text-styling.mdx +50 -0
- package/templates/react-router/content/quickstart.mdx +60 -0
- package/templates/react-router/heyo-docs.config.ts +24 -2
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Create Heyo Docs
|
|
2
|
+
|
|
3
|
+
Create a standalone, production-ready documentation site with Heyo Docs. Choose React Router, Next.js, or Astro, plus a built-in theme and deployment target.
|
|
4
|
+
|
|
5
|
+
## Create a project
|
|
6
|
+
|
|
7
|
+
Run the creator without arguments to choose the project directory, framework,
|
|
8
|
+
deployment target, theme, and package manager interactively. It prints the
|
|
9
|
+
appropriate `cd` and development-server commands when it finishes.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# pnpm
|
|
13
|
+
pnpm create @heyo-sh/heyo-docs
|
|
14
|
+
|
|
15
|
+
# npm
|
|
16
|
+
npm create @heyo-sh/heyo-docs@latest
|
|
17
|
+
|
|
18
|
+
# Yarn
|
|
19
|
+
yarn dlx @heyo-sh/create-heyo-docs
|
|
20
|
+
|
|
21
|
+
# Bun
|
|
22
|
+
bun create @heyo-sh/heyo-docs
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The creator works with pnpm, npm, Yarn, and Bun.
|
|
26
|
+
|
|
27
|
+
## Options
|
|
28
|
+
|
|
29
|
+
Passing options makes the creator non-interactive; include a project-directory
|
|
30
|
+
argument when using them in automation.
|
|
31
|
+
|
|
32
|
+
| Option | Values |
|
|
33
|
+
| ------------------- | ------------------------------- |
|
|
34
|
+
| `--template` | `react-router`, `next`, `astro` |
|
|
35
|
+
| `--theme` | `grain`, `shade`, `moss` |
|
|
36
|
+
| `--deployment` | `cloudflare`, `vercel`, `later` |
|
|
37
|
+
| `--package-manager` | `bun`, `pnpm`, `npm`, `yarn` |
|
|
38
|
+
| `--no-install` | Skip dependency installation |
|
|
39
|
+
|
|
40
|
+
Read the [full documentation](https://docs.heyo.sh) for configuration, content, components, framework integrations, and deployment.
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
[MIT](https://github.com/heyo-sh/heyo-docs/blob/main/LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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":";AAYA,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;AAqD7B,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,349 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { realpathSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import * as p from "@clack/prompts";
|
|
7
|
+
|
|
8
|
+
// src/package-manager.ts
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
10
|
+
var FALLBACK_VERSIONS = {
|
|
11
|
+
bun: "1.3.1",
|
|
12
|
+
pnpm: "10.17.0",
|
|
13
|
+
npm: "11.6.0",
|
|
14
|
+
yarn: "4.9.4"
|
|
15
|
+
};
|
|
16
|
+
function detectPackageManager(userAgent = process.env.npm_config_user_agent ?? "") {
|
|
17
|
+
const match = userAgent.match(/(?:^|\s)(bun|pnpm|npm|yarn)\/([^\s]+)/);
|
|
18
|
+
if (!match)
|
|
19
|
+
return { name: "npm" };
|
|
20
|
+
return { name: match[1], version: match[2] };
|
|
21
|
+
}
|
|
22
|
+
function packageManagerField(manager, detected = detectPackageManager()) {
|
|
23
|
+
if (manager === detected.name && detected.version)
|
|
24
|
+
return `${manager}@${detected.version}`;
|
|
25
|
+
const executable = manager === "yarn" ? "yarn" : manager;
|
|
26
|
+
try {
|
|
27
|
+
const result = spawnSync(executable, ["--version"], {
|
|
28
|
+
encoding: "utf8"
|
|
29
|
+
});
|
|
30
|
+
const version = result.stdout?.trim();
|
|
31
|
+
if (result.status === 0 && version && /^\d+(?:\.\d+)+/.test(version))
|
|
32
|
+
return `${manager}@${version}`;
|
|
33
|
+
} catch {}
|
|
34
|
+
return `${manager}@${FALLBACK_VERSIONS[manager]}`;
|
|
35
|
+
}
|
|
36
|
+
function packageManagerInstallCommand(manager) {
|
|
37
|
+
return manager === "yarn" ? ["yarn"] : [manager, "install"];
|
|
38
|
+
}
|
|
39
|
+
function packageManagerRunCommand(manager, script) {
|
|
40
|
+
if (manager === "npm")
|
|
41
|
+
return `npm run ${script}`;
|
|
42
|
+
if (manager === "yarn")
|
|
43
|
+
return `yarn ${script}`;
|
|
44
|
+
return `${manager} run ${script}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/project-name.ts
|
|
48
|
+
var PROJECT_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/i;
|
|
49
|
+
function projectNameError(value) {
|
|
50
|
+
if (!value.trim())
|
|
51
|
+
return "Enter a project name.";
|
|
52
|
+
if (!PROJECT_NAME_PATTERN.test(value))
|
|
53
|
+
return "Use letters, numbers and hyphens only.";
|
|
54
|
+
}
|
|
55
|
+
function assertProjectName(value) {
|
|
56
|
+
const error = projectNameError(value);
|
|
57
|
+
if (error)
|
|
58
|
+
throw new Error(error);
|
|
59
|
+
return value.trim();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/scaffold.ts
|
|
63
|
+
import { spawn } from "node:child_process";
|
|
64
|
+
import { existsSync } from "node:fs";
|
|
65
|
+
import { mkdir as mkdir2, readdir as readdir2 } from "node:fs/promises";
|
|
66
|
+
import { join as join2, resolve } from "node:path";
|
|
67
|
+
|
|
68
|
+
// src/utils.ts
|
|
69
|
+
import {
|
|
70
|
+
cp,
|
|
71
|
+
mkdir,
|
|
72
|
+
readFile,
|
|
73
|
+
readdir,
|
|
74
|
+
rm,
|
|
75
|
+
stat,
|
|
76
|
+
writeFile
|
|
77
|
+
} from "node:fs/promises";
|
|
78
|
+
import { dirname, join } from "node:path";
|
|
79
|
+
function replacePlaceholders(source, values) {
|
|
80
|
+
return source.replace(/\{\{([A-Z0-9_]+)\}\}/g, (placeholder, key) => values[key] ?? placeholder);
|
|
81
|
+
}
|
|
82
|
+
function mergePackageJson(base, overlay) {
|
|
83
|
+
const merged = { ...base };
|
|
84
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
85
|
+
const current = merged[key];
|
|
86
|
+
if (isRecord(current) && isRecord(value))
|
|
87
|
+
merged[key] = mergePackageJson(current, value);
|
|
88
|
+
else
|
|
89
|
+
merged[key] = value;
|
|
90
|
+
}
|
|
91
|
+
return merged;
|
|
92
|
+
}
|
|
93
|
+
async function copyTemplate(source, destination, placeholders) {
|
|
94
|
+
await cp(source, destination, { recursive: true, force: true });
|
|
95
|
+
await replacePlaceholdersAtPath(destination, placeholders);
|
|
96
|
+
}
|
|
97
|
+
async function replacePlaceholdersAtPath(path, values) {
|
|
98
|
+
if (!(await stat(path)).isDirectory()) {
|
|
99
|
+
const contents = await readFile(path, "utf8");
|
|
100
|
+
await writeFile(path, replacePlaceholders(contents, values));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const entries = await readdir(path, { withFileTypes: true });
|
|
104
|
+
await Promise.all(entries.map((entry) => replacePlaceholdersAtPath(join(path, entry.name), values)));
|
|
105
|
+
}
|
|
106
|
+
async function writeJson(path, data) {
|
|
107
|
+
await mkdir(dirname(path), { recursive: true });
|
|
108
|
+
await writeFile(path, `${JSON.stringify(data, null, 2)}
|
|
109
|
+
`);
|
|
110
|
+
}
|
|
111
|
+
async function readJson(path) {
|
|
112
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
113
|
+
}
|
|
114
|
+
function isRecord(value) {
|
|
115
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/scaffold.ts
|
|
119
|
+
var packageRoot = resolve(import.meta.dirname, "..");
|
|
120
|
+
async function scaffoldProject(options) {
|
|
121
|
+
const cwd = options.cwd ?? process.cwd();
|
|
122
|
+
const projectName = assertProjectName(options.projectName);
|
|
123
|
+
const projectPath = resolve(cwd, projectName);
|
|
124
|
+
if (existsSync(projectPath))
|
|
125
|
+
throw new Error(`Directory already exists: ${projectPath}`);
|
|
126
|
+
const placeholders = {
|
|
127
|
+
PROJECT_NAME: projectName,
|
|
128
|
+
HEYO_DOCS_VERSION: options.heyoDocsVersion ?? "0.1.0",
|
|
129
|
+
PACKAGE_MANAGER: packageManagerField(options.packageManager),
|
|
130
|
+
THEME: options.theme
|
|
131
|
+
};
|
|
132
|
+
const templatePath = join2(packageRoot, "templates", options.template);
|
|
133
|
+
const deploymentPath = join2(packageRoot, "deployments", options.deployment, options.template);
|
|
134
|
+
await mkdir2(projectPath, { recursive: true });
|
|
135
|
+
await copyTemplate(templatePath, projectPath, placeholders);
|
|
136
|
+
const basePackage = await readJson(join2(projectPath, "package.json"));
|
|
137
|
+
const overlayPackage = options.deployment === "later" ? {} : await readJson(join2(deploymentPath, "package.json"));
|
|
138
|
+
if (options.deployment !== "later") {
|
|
139
|
+
await copyOverlay(deploymentPath, projectPath, placeholders);
|
|
140
|
+
}
|
|
141
|
+
await writeJson(join2(projectPath, "package.json"), mergePackageJson(basePackage, overlayPackage));
|
|
142
|
+
if (options.install)
|
|
143
|
+
await installDependencies(projectPath, options.packageManager);
|
|
144
|
+
return { projectPath };
|
|
145
|
+
}
|
|
146
|
+
async function copyOverlay(source, destination, placeholders) {
|
|
147
|
+
const entries = await readdir2(source, { withFileTypes: true });
|
|
148
|
+
await Promise.all(entries.filter((entry) => entry.name !== "package.json").map(async (entry) => {
|
|
149
|
+
const sourcePath = join2(source, entry.name);
|
|
150
|
+
const destinationPath = join2(destination, entry.name);
|
|
151
|
+
return copyTemplate(sourcePath, destinationPath, placeholders);
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
async function installDependencies(projectPath, packageManager) {
|
|
155
|
+
const command = packageManagerInstallCommand(packageManager);
|
|
156
|
+
const [executable, ...arguments_] = command;
|
|
157
|
+
await new Promise((resolveInstall, rejectInstall) => {
|
|
158
|
+
const child = spawn(executable, arguments_, {
|
|
159
|
+
cwd: projectPath,
|
|
160
|
+
stdio: "inherit"
|
|
161
|
+
});
|
|
162
|
+
child.once("error", rejectInstall);
|
|
163
|
+
child.once("close", (exitCode) => {
|
|
164
|
+
if (exitCode === 0)
|
|
165
|
+
return resolveInstall();
|
|
166
|
+
rejectInstall(new Error(`Dependency installation failed with ${command.join(" ")}.`));
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/index.ts
|
|
172
|
+
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]";
|
|
173
|
+
var TEMPLATE_OPTIONS = [
|
|
174
|
+
{ value: "react-router", label: "React Router" },
|
|
175
|
+
{ value: "next", label: "Next.js" },
|
|
176
|
+
{ value: "astro", label: "Astro" }
|
|
177
|
+
];
|
|
178
|
+
var DEPLOYMENT_OPTIONS = [
|
|
179
|
+
{ value: "cloudflare", label: "Cloudflare" },
|
|
180
|
+
{ value: "vercel", label: "Vercel" },
|
|
181
|
+
{ value: "later", label: "Configure later" }
|
|
182
|
+
];
|
|
183
|
+
var THEME_OPTIONS = [
|
|
184
|
+
{ value: "grain", label: "Grain" },
|
|
185
|
+
{ value: "shade", label: "Shade" },
|
|
186
|
+
{ value: "moss", label: "Moss" },
|
|
187
|
+
{
|
|
188
|
+
value: "dripper",
|
|
189
|
+
label: "Dripper — Soon",
|
|
190
|
+
hint: "Unavailable in this MVP"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
value: "fixed-gear",
|
|
194
|
+
label: "Fixed Gear — Soon",
|
|
195
|
+
hint: "Unavailable in this MVP"
|
|
196
|
+
}
|
|
197
|
+
];
|
|
198
|
+
var PACKAGE_MANAGER_OPTIONS = [
|
|
199
|
+
{ value: "bun", label: "bun" },
|
|
200
|
+
{ value: "pnpm", label: "pnpm" },
|
|
201
|
+
{ value: "npm", label: "npm" },
|
|
202
|
+
{ value: "yarn", label: "yarn" }
|
|
203
|
+
];
|
|
204
|
+
if (isMainModule()) {
|
|
205
|
+
run(process.argv.slice(2)).catch((error) => {
|
|
206
|
+
p.log.error(error instanceof Error ? error.message : String(error));
|
|
207
|
+
process.exitCode = 1;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function isMainModule() {
|
|
211
|
+
const entryPoint = process.argv[1];
|
|
212
|
+
if (!entryPoint)
|
|
213
|
+
return false;
|
|
214
|
+
try {
|
|
215
|
+
return realpathSync(entryPoint) === fileURLToPath(import.meta.url);
|
|
216
|
+
} catch {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function run(argv = process.argv.slice(2)) {
|
|
221
|
+
const parsed = parseArguments(argv);
|
|
222
|
+
if (parsed.showHelp) {
|
|
223
|
+
p.note(USAGE, "@heyo-sh/create-heyo-docs");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const options = parsed.interactive ? await askQuestions(parsed.options) : parsed.options;
|
|
227
|
+
const spinner2 = p.spinner();
|
|
228
|
+
spinner2.start("Creating your Heyo Docs project");
|
|
229
|
+
try {
|
|
230
|
+
await scaffoldProject(options);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
spinner2.stop("Unable to create your documentation project");
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
spinner2.stop("Your documentation project is ready");
|
|
236
|
+
const install = options.install ? "" : `
|
|
237
|
+
${options.packageManager} install`;
|
|
238
|
+
p.note(`cd ${options.projectName}${install}
|
|
239
|
+
${packageManagerRunCommand(options.packageManager, "dev")}`, "Next steps");
|
|
240
|
+
p.outro("Happy documenting.");
|
|
241
|
+
}
|
|
242
|
+
function parseArguments(argv) {
|
|
243
|
+
const detected = detectPackageManager();
|
|
244
|
+
const options = {
|
|
245
|
+
projectName: "",
|
|
246
|
+
template: "react-router",
|
|
247
|
+
deployment: "later",
|
|
248
|
+
theme: "grain",
|
|
249
|
+
packageManager: detected.name,
|
|
250
|
+
install: true
|
|
251
|
+
};
|
|
252
|
+
let explicit = false;
|
|
253
|
+
let showHelp = false;
|
|
254
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
255
|
+
const value = argv[index];
|
|
256
|
+
if (!value.startsWith("-")) {
|
|
257
|
+
options.projectName ||= value;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
explicit = true;
|
|
261
|
+
if (value === "--template") {
|
|
262
|
+
options.template = readEnum(argv[++index], ["react-router", "next", "astro"], "template");
|
|
263
|
+
} else if (value === "--deployment") {
|
|
264
|
+
options.deployment = readEnum(argv[++index], ["cloudflare", "vercel", "later"], "deployment");
|
|
265
|
+
} else if (value === "--theme") {
|
|
266
|
+
options.theme = readEnum(argv[++index], ["grain", "shade", "moss"], "theme");
|
|
267
|
+
} else if (value === "--package-manager") {
|
|
268
|
+
options.packageManager = readEnum(argv[++index], ["bun", "pnpm", "npm", "yarn"], "package manager");
|
|
269
|
+
} else if (value === "--no-install") {
|
|
270
|
+
options.install = false;
|
|
271
|
+
} else if (value === "--install") {
|
|
272
|
+
options.install = true;
|
|
273
|
+
} else if (value === "--help" || value === "-h") {
|
|
274
|
+
showHelp = true;
|
|
275
|
+
} else {
|
|
276
|
+
throw new Error(`Unknown option: ${value}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return { options, interactive: !explicit && !options.projectName, showHelp };
|
|
280
|
+
}
|
|
281
|
+
async function askQuestions(defaults) {
|
|
282
|
+
p.intro("Create Heyo Docs");
|
|
283
|
+
const projectName = await p.text({
|
|
284
|
+
message: "Project name",
|
|
285
|
+
placeholder: "my-docs",
|
|
286
|
+
defaultValue: "my-docs",
|
|
287
|
+
validate: projectNameError
|
|
288
|
+
});
|
|
289
|
+
if (p.isCancel(projectName))
|
|
290
|
+
cancelCreation();
|
|
291
|
+
const template = await selectAvailable("Template", TEMPLATE_OPTIONS, [
|
|
292
|
+
"react-router",
|
|
293
|
+
"next",
|
|
294
|
+
"astro"
|
|
295
|
+
]);
|
|
296
|
+
const deployment = await selectAvailable("Deployment", DEPLOYMENT_OPTIONS, ["cloudflare", "vercel", "later"], defaults.deployment);
|
|
297
|
+
const theme = await selectAvailable("Theme", THEME_OPTIONS, [
|
|
298
|
+
"grain",
|
|
299
|
+
"shade",
|
|
300
|
+
"moss"
|
|
301
|
+
]);
|
|
302
|
+
const packageManager = await selectAvailable("Package manager", PACKAGE_MANAGER_OPTIONS, ["bun", "pnpm", "npm", "yarn"], defaults.packageManager);
|
|
303
|
+
const install = await p.confirm({
|
|
304
|
+
message: "Install dependencies?",
|
|
305
|
+
initialValue: true
|
|
306
|
+
});
|
|
307
|
+
if (p.isCancel(install))
|
|
308
|
+
cancelCreation();
|
|
309
|
+
return {
|
|
310
|
+
projectName,
|
|
311
|
+
template,
|
|
312
|
+
deployment,
|
|
313
|
+
theme,
|
|
314
|
+
packageManager,
|
|
315
|
+
install
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async function selectAvailable(message, options, available, initialValue) {
|
|
319
|
+
for (;; ) {
|
|
320
|
+
const answer = await p.select({ message, options, initialValue });
|
|
321
|
+
if (p.isCancel(answer))
|
|
322
|
+
cancelCreation();
|
|
323
|
+
if (isOneOf(answer, available))
|
|
324
|
+
return answer;
|
|
325
|
+
p.log.warn("That option is planned but not available in this MVP.");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function isOneOf(value, values) {
|
|
329
|
+
return values.some((candidate) => candidate === value);
|
|
330
|
+
}
|
|
331
|
+
function cancelCreation() {
|
|
332
|
+
p.cancel("Creation cancelled.");
|
|
333
|
+
process.exit(0);
|
|
334
|
+
}
|
|
335
|
+
function readEnum(value, allowed, label) {
|
|
336
|
+
if (value && isOneOf(value, allowed))
|
|
337
|
+
return value;
|
|
338
|
+
throw new Error(`Use one of ${allowed.join(", ")} for ${label}.`);
|
|
339
|
+
}
|
|
340
|
+
export {
|
|
341
|
+
scaffoldProject,
|
|
342
|
+
run,
|
|
343
|
+
replacePlaceholders,
|
|
344
|
+
parseArguments,
|
|
345
|
+
packageManagerRunCommand,
|
|
346
|
+
packageManagerField,
|
|
347
|
+
mergePackageJson,
|
|
348
|
+
detectPackageManager
|
|
349
|
+
};
|
|
@@ -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":"AAEA,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,CAeR;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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,wBAAsB,eAAe,CACnC,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CA0ClC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type Template = "react-router" | "next" | "astro";
|
|
2
|
+
export type Deployment = "cloudflare" | "vercel" | "later";
|
|
3
|
+
export type Theme = "grain" | "shade" | "moss";
|
|
4
|
+
export type PackageManager = "bun" | "pnpm" | "npm" | "yarn";
|
|
5
|
+
export interface CreateOptions {
|
|
6
|
+
projectName: string;
|
|
7
|
+
template: Template;
|
|
8
|
+
deployment: Deployment;
|
|
9
|
+
theme: Theme;
|
|
10
|
+
packageManager: PackageManager;
|
|
11
|
+
install: boolean;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
heyoDocsVersion?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface DetectedPackageManager {
|
|
16
|
+
name: PackageManager;
|
|
17
|
+
version?: string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,MAAM,GAAG,OAAO,CAAC;AACzD,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAC/C,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function replacePlaceholders(source: string, values: Record<string, string>): string;
|
|
2
|
+
export declare function mergePackageJson<T extends Record<string, unknown>>(base: T, overlay: Record<string, unknown>): T;
|
|
3
|
+
export declare function copyTemplate(source: string, destination: string, placeholders: Record<string, string>): Promise<void>;
|
|
4
|
+
export declare function replacePlaceholdersInDirectory(directory: string, values: Record<string, string>): Promise<void>;
|
|
5
|
+
export declare function writeJson(path: string, data: unknown): Promise<void>;
|
|
6
|
+
export declare function readJson<T>(path: string): Promise<T>;
|
|
7
|
+
export declare function emptyDirectory(path: string): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAWA,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAKR;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,CAAC,CASH;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAOf;AAoBD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAE1D;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyo-sh/create-heyo-docs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Create a standalone Heyo Docs documentation project.",
|
|
5
5
|
"homepage": "https://heyo.sh",
|
|
6
6
|
"repository": {
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"type": "module",
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20.11.0"
|
|
17
|
+
},
|
|
15
18
|
"bin": {
|
|
16
19
|
"create-heyo-docs": "./dist/index.js"
|
|
17
20
|
},
|
|
@@ -28,7 +31,7 @@
|
|
|
28
31
|
},
|
|
29
32
|
"scripts": {
|
|
30
33
|
"dev": "bun run build --watch",
|
|
31
|
-
"build": "bun build src/index.ts --outdir dist --target
|
|
34
|
+
"build": "bun build src/index.ts --outdir dist --target node --external @clack/prompts && bun run build:types",
|
|
32
35
|
"build:types": "tsc -p tsconfig.build.json",
|
|
33
36
|
"typecheck": "tsc -p tsconfig.json",
|
|
34
37
|
"test": "bun test"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Basic Configuration
|
|
3
|
+
description: Set the identity, content source, and sidebar structure for a Heyo Docs site.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Basic Configuration
|
|
7
|
+
|
|
8
|
+
`heyo-docs.config.ts` is the single source of truth for a Heyo Docs site.
|
|
9
|
+
The framework integration and the documentation UI read the same validated
|
|
10
|
+
object, so a change to navigation or metadata does not need to be repeated in
|
|
11
|
+
multiple places.
|
|
12
|
+
|
|
13
|
+
## Start with the site model
|
|
14
|
+
|
|
15
|
+
The generated project already includes a working configuration. Update the
|
|
16
|
+
identity fields first, then point `content` at the directory that contains
|
|
17
|
+
your MDX files.
|
|
18
|
+
|
|
19
|
+
<CodeBlock language="ts" title="heyo-docs.config.ts" showLineNumbers>
|
|
20
|
+
{`import { heyoDocs } from "@heyo-sh/heyo-docs";
|
|
21
|
+
|
|
22
|
+
export default heyoDocs({
|
|
23
|
+
title: "{{PROJECT_NAME}}",
|
|
24
|
+
description: "Guides and reference for {{PROJECT_NAME}}.",
|
|
25
|
+
content: "./content",
|
|
26
|
+
theme: "grain",
|
|
27
|
+
mode: "system",
|
|
28
|
+
branding: { name: "{{PROJECT_NAME}}" },
|
|
29
|
+
});`}
|
|
30
|
+
</CodeBlock>
|
|
31
|
+
|
|
32
|
+
Set `siteUrl` to the final public origin before publishing. It is used for
|
|
33
|
+
canonical URLs, social metadata, the sitemap, RSS, and AI-facing discovery
|
|
34
|
+
files.
|
|
35
|
+
|
|
36
|
+
## Organize the sidebar
|
|
37
|
+
|
|
38
|
+
Use `groups` to define the order readers see. A group contains named sections
|
|
39
|
+
and their MDX page references; a reference is relative to `content` and does
|
|
40
|
+
not include the `.mdx` extension.
|
|
41
|
+
|
|
42
|
+
<CodeBlock language="ts" title="heyo-docs.config.ts">
|
|
43
|
+
{`groups: [
|
|
44
|
+
{
|
|
45
|
+
group: "Documentation",
|
|
46
|
+
icon: "globe",
|
|
47
|
+
sections: [
|
|
48
|
+
{
|
|
49
|
+
section: "Get Started",
|
|
50
|
+
icon: "lightbulb",
|
|
51
|
+
pages: ["quickstart", "configuration"],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
section: "Essentials",
|
|
55
|
+
icon: "book",
|
|
56
|
+
pages: ["essentials/text-styling", "essentials/code-blocks"],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
],`}
|
|
61
|
+
</CodeBlock>
|
|
62
|
+
|
|
63
|
+
The order is meaningful: it controls the sidebar and the previous/next links at
|
|
64
|
+
the end of each article. Use a page object with `title` and `src` when a
|
|
65
|
+
sidebar entry should point to a page outside the local documentation.
|
|
66
|
+
|
|
67
|
+
## Verify the result
|
|
68
|
+
|
|
69
|
+
Run the project's typecheck and build commands after changing configuration.
|
|
70
|
+
They resolve each configured MDX page and report missing paths or malformed
|
|
71
|
+
navigation before the site is deployed.
|
|
72
|
+
|
|
73
|
+
<Callout type="info" title="Keep page metadata close to the page">
|
|
74
|
+
Put a page's <code>title</code> and <code>description</code> in its MDX
|
|
75
|
+
frontmatter. Keep shared site settings in <code>heyo-docs.config.ts</code>.
|
|
76
|
+
</Callout>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Deploying
|
|
3
|
+
description: Build and publish your Heyo Docs site with the deployment target chosen during setup.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deploying
|
|
7
|
+
|
|
8
|
+
A Heyo Docs site is built as part of the framework application. The creator asks
|
|
9
|
+
for a deployment target when the project is created and adds the corresponding
|
|
10
|
+
configuration, so the same MDX content, navigation, search, and metadata are
|
|
11
|
+
used locally and in production.
|
|
12
|
+
|
|
13
|
+
## Choose the target during setup
|
|
14
|
+
|
|
15
|
+
Select Vercel or Cloudflare when running the creator if you already know where
|
|
16
|
+
the site will live. The generated project includes the adapter and deployment
|
|
17
|
+
configuration required by that platform. You can also choose to configure
|
|
18
|
+
deployment later and keep the starter focused on local development.
|
|
19
|
+
|
|
20
|
+
## Build before publishing
|
|
21
|
+
|
|
22
|
+
Run the production build on your machine before creating a deployment. It
|
|
23
|
+
resolves every configured page, validates the navigation tree, and generates
|
|
24
|
+
the sitemap, RSS feed, robots file, and AI-facing documentation endpoints.
|
|
25
|
+
|
|
26
|
+
<CodeBlock language="bash" title="Terminal">
|
|
27
|
+
{"bun run build"}
|
|
28
|
+
</CodeBlock>
|
|
29
|
+
|
|
30
|
+
Use the equivalent `npm run build`, `pnpm build`, or `yarn build` command
|
|
31
|
+
when the project uses a different package manager.
|
|
32
|
+
|
|
33
|
+
<Callout type="tip" title="Set the canonical URL">
|
|
34
|
+
Add the final public origin as <code>siteUrl</code> in
|
|
35
|
+
<code>heyo-docs.config.ts</code> before the first production release. It keeps
|
|
36
|
+
canonical links, social metadata, and generated discovery files consistent.
|
|
37
|
+
</Callout>
|
|
38
|
+
|
|
39
|
+
## Publish the project
|
|
40
|
+
|
|
41
|
+
For a generated Vercel or Cloudflare project, connect the repository in the
|
|
42
|
+
provider dashboard or run the deployment script included by the selected setup.
|
|
43
|
+
The provider builds the application with the same command you verified locally.
|
|
44
|
+
|
|
45
|
+
<Steps>
|
|
46
|
+
<Step title="Push the documentation source">
|
|
47
|
+
Commit the MDX content and <code>heyo-docs.config.ts</code> together so the
|
|
48
|
+
deployed navigation matches the reviewed pages.
|
|
49
|
+
</Step>
|
|
50
|
+
<Step title="Create a preview">
|
|
51
|
+
Review the provider's preview URL for layout, links, search, and metadata.
|
|
52
|
+
</Step>
|
|
53
|
+
<Step title="Promote the production build">
|
|
54
|
+
Publish once the preview is correct and the configured <code>siteUrl</code>
|
|
55
|
+
matches the public domain.
|
|
56
|
+
</Step>
|
|
57
|
+
</Steps>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Callouts
|
|
3
|
+
description: Highlight prerequisites, tips, warnings, and successful outcomes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Callouts
|
|
7
|
+
|
|
8
|
+
Use `Callout` when an important note should stand apart from the surrounding
|
|
9
|
+
prose. It works well for a prerequisite, a preferred approach, a warning, or a
|
|
10
|
+
successful result.
|
|
11
|
+
|
|
12
|
+
## Choose the right emphasis
|
|
13
|
+
|
|
14
|
+
Use `note` or `info` for context, `tip` for a recommended approach, and
|
|
15
|
+
`check` for a completed outcome. Reserve `warning` and `danger` for cases
|
|
16
|
+
where missing the message has a real consequence.
|
|
17
|
+
|
|
18
|
+
<Callout type="tip" title="Keep examples focused">
|
|
19
|
+
Show one idea at a time so readers can apply it quickly.
|
|
20
|
+
</Callout>
|
|
21
|
+
|
|
22
|
+
<Callout type="warning" title="Preview before publishing">
|
|
23
|
+
Run the production build locally after changing navigation or MDX.
|
|
24
|
+
</Callout>
|
|
25
|
+
|
|
26
|
+
## Add richer guidance
|
|
27
|
+
|
|
28
|
+
Pass the message as children when it needs Markdown or another MDX component.
|
|
29
|
+
|
|
30
|
+
<Callout type="info" title="Configuration and content work together">
|
|
31
|
+
Navigation belongs in <code>heyo-docs.config.ts</code>; page titles and
|
|
32
|
+
descriptions belong in the page frontmatter.
|
|
33
|
+
</Callout>
|
|
34
|
+
|
|
35
|
+
Keep each callout focused on one decision. A long sequence of status messages is
|
|
36
|
+
usually clearer as regular sections or a numbered procedure.
|