@raystack/chronicle 0.1.0-canary.e11f924 → 0.1.0-canary.f94fdd7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +264 -105
- package/package.json +4 -3
- package/src/cli/commands/build.ts +13 -14
- package/src/cli/commands/dev.ts +12 -13
- package/src/cli/commands/init.ts +70 -9
- package/src/cli/commands/serve.ts +13 -14
- package/src/cli/commands/start.ts +12 -13
- package/src/cli/utils/config.ts +1 -1
- package/src/cli/utils/index.ts +1 -0
- package/src/cli/utils/resolve.ts +4 -0
- package/src/cli/utils/scaffold.ts +131 -0
- package/src/lib/config.ts +8 -0
- package/src/lib/source.ts +1 -1
- package/tsconfig.json +30 -0
package/dist/cli/index.js
CHANGED
|
@@ -9044,8 +9044,9 @@ var {
|
|
|
9044
9044
|
} = import__.default;
|
|
9045
9045
|
|
|
9046
9046
|
// src/cli/commands/init.ts
|
|
9047
|
-
import
|
|
9048
|
-
import
|
|
9047
|
+
import { execSync as execSync2 } from "child_process";
|
|
9048
|
+
import fs3 from "fs";
|
|
9049
|
+
import path4 from "path";
|
|
9049
9050
|
|
|
9050
9051
|
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
9051
9052
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -9582,6 +9583,151 @@ var $stringify = publicApi.stringify;
|
|
|
9582
9583
|
var $visit = visit.visit;
|
|
9583
9584
|
var $visitAsync = visit.visitAsync;
|
|
9584
9585
|
|
|
9586
|
+
// src/cli/utils/config.ts
|
|
9587
|
+
import fs from "fs";
|
|
9588
|
+
import path from "path";
|
|
9589
|
+
function resolveConfigPath(contentDir) {
|
|
9590
|
+
const cwdPath = path.join(process.cwd(), "chronicle.yaml");
|
|
9591
|
+
if (fs.existsSync(cwdPath))
|
|
9592
|
+
return cwdPath;
|
|
9593
|
+
const contentPath = path.join(contentDir, "chronicle.yaml");
|
|
9594
|
+
if (fs.existsSync(contentPath))
|
|
9595
|
+
return contentPath;
|
|
9596
|
+
return null;
|
|
9597
|
+
}
|
|
9598
|
+
function loadCLIConfig(contentDir) {
|
|
9599
|
+
const configPath = resolveConfigPath(contentDir);
|
|
9600
|
+
if (!configPath) {
|
|
9601
|
+
console.log(source_default.red("Error: chronicle.yaml not found in"), process.cwd(), "or", contentDir);
|
|
9602
|
+
console.log(source_default.gray(`Run 'chronicle init' to create one`));
|
|
9603
|
+
process.exit(1);
|
|
9604
|
+
}
|
|
9605
|
+
const config = $parse(fs.readFileSync(configPath, "utf-8"));
|
|
9606
|
+
return {
|
|
9607
|
+
config,
|
|
9608
|
+
configPath,
|
|
9609
|
+
contentDir
|
|
9610
|
+
};
|
|
9611
|
+
}
|
|
9612
|
+
// src/cli/utils/process.ts
|
|
9613
|
+
function attachLifecycleHandlers(child) {
|
|
9614
|
+
child.on("close", (code) => process.exit(code ?? 0));
|
|
9615
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
9616
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
9617
|
+
}
|
|
9618
|
+
// src/cli/utils/scaffold.ts
|
|
9619
|
+
import { execSync } from "child_process";
|
|
9620
|
+
import { createRequire as createRequire2 } from "module";
|
|
9621
|
+
import fs2 from "fs";
|
|
9622
|
+
import path3 from "path";
|
|
9623
|
+
|
|
9624
|
+
// src/cli/utils/resolve.ts
|
|
9625
|
+
import path2 from "path";
|
|
9626
|
+
import { fileURLToPath } from "url";
|
|
9627
|
+
var PACKAGE_ROOT = path2.resolve(path2.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9628
|
+
|
|
9629
|
+
// src/cli/utils/scaffold.ts
|
|
9630
|
+
var COPY_FILES = ["src", "source.config.ts", "tsconfig.json"];
|
|
9631
|
+
function copyRecursive(src, dest) {
|
|
9632
|
+
const stat = fs2.statSync(src);
|
|
9633
|
+
if (stat.isDirectory()) {
|
|
9634
|
+
fs2.mkdirSync(dest, { recursive: true });
|
|
9635
|
+
for (const entry of fs2.readdirSync(src)) {
|
|
9636
|
+
copyRecursive(path3.join(src, entry), path3.join(dest, entry));
|
|
9637
|
+
}
|
|
9638
|
+
} else {
|
|
9639
|
+
fs2.copyFileSync(src, dest);
|
|
9640
|
+
}
|
|
9641
|
+
}
|
|
9642
|
+
function ensureRemoved(targetPath) {
|
|
9643
|
+
try {
|
|
9644
|
+
fs2.lstatSync(targetPath);
|
|
9645
|
+
fs2.rmSync(targetPath, { recursive: true, force: true });
|
|
9646
|
+
} catch {}
|
|
9647
|
+
}
|
|
9648
|
+
function detectPackageManager() {
|
|
9649
|
+
if (process.env.npm_config_user_agent) {
|
|
9650
|
+
return process.env.npm_config_user_agent.split("/")[0];
|
|
9651
|
+
}
|
|
9652
|
+
const cwd = process.cwd();
|
|
9653
|
+
if (fs2.existsSync(path3.join(cwd, "bun.lock")) || fs2.existsSync(path3.join(cwd, "bun.lockb")))
|
|
9654
|
+
return "bun";
|
|
9655
|
+
if (fs2.existsSync(path3.join(cwd, "pnpm-lock.yaml")))
|
|
9656
|
+
return "pnpm";
|
|
9657
|
+
if (fs2.existsSync(path3.join(cwd, "yarn.lock")))
|
|
9658
|
+
return "yarn";
|
|
9659
|
+
return "npm";
|
|
9660
|
+
}
|
|
9661
|
+
function generateNextConfig(scaffoldPath) {
|
|
9662
|
+
const config = `import { createMDX } from 'fumadocs-mdx/next'
|
|
9663
|
+
|
|
9664
|
+
const withMDX = createMDX()
|
|
9665
|
+
|
|
9666
|
+
/** @type {import('next').NextConfig} */
|
|
9667
|
+
const nextConfig = {
|
|
9668
|
+
reactStrictMode: true,
|
|
9669
|
+
}
|
|
9670
|
+
|
|
9671
|
+
export default withMDX(nextConfig)
|
|
9672
|
+
`;
|
|
9673
|
+
fs2.writeFileSync(path3.join(scaffoldPath, "next.config.mjs"), config);
|
|
9674
|
+
}
|
|
9675
|
+
function createPackageJson() {
|
|
9676
|
+
return {
|
|
9677
|
+
name: "chronicle-docs",
|
|
9678
|
+
private: true,
|
|
9679
|
+
dependencies: {
|
|
9680
|
+
"@raystack/chronicle": "latest"
|
|
9681
|
+
},
|
|
9682
|
+
devDependencies: {
|
|
9683
|
+
"@raystack/tools-config": "0.56.0",
|
|
9684
|
+
"openapi-types": "^12.1.3",
|
|
9685
|
+
typescript: "5.9.3",
|
|
9686
|
+
"@types/react": "^19.2.10",
|
|
9687
|
+
"@types/node": "^25.1.0"
|
|
9688
|
+
}
|
|
9689
|
+
};
|
|
9690
|
+
}
|
|
9691
|
+
function ensureDeps() {
|
|
9692
|
+
const cwd = process.cwd();
|
|
9693
|
+
const cwdPkgJson = path3.join(cwd, "package.json");
|
|
9694
|
+
const cwdNodeModules = path3.join(cwd, "node_modules");
|
|
9695
|
+
if (fs2.existsSync(cwdPkgJson) && fs2.existsSync(cwdNodeModules)) {
|
|
9696
|
+
return;
|
|
9697
|
+
}
|
|
9698
|
+
if (!fs2.existsSync(cwdPkgJson)) {
|
|
9699
|
+
fs2.writeFileSync(cwdPkgJson, JSON.stringify(createPackageJson(), null, 2) + `
|
|
9700
|
+
`);
|
|
9701
|
+
}
|
|
9702
|
+
if (!fs2.existsSync(cwdNodeModules)) {
|
|
9703
|
+
const pm = detectPackageManager();
|
|
9704
|
+
console.log(source_default.cyan(`Installing dependencies with ${pm}...`));
|
|
9705
|
+
execSync(`${pm} install`, { cwd, stdio: "inherit" });
|
|
9706
|
+
}
|
|
9707
|
+
}
|
|
9708
|
+
function resolveNextCli() {
|
|
9709
|
+
const cwdRequire = createRequire2(path3.join(process.cwd(), "package.json"));
|
|
9710
|
+
return cwdRequire.resolve("next/dist/bin/next");
|
|
9711
|
+
}
|
|
9712
|
+
function scaffoldDir(contentDir) {
|
|
9713
|
+
const scaffoldPath = path3.join(process.cwd(), ".chronicle");
|
|
9714
|
+
if (!fs2.existsSync(scaffoldPath)) {
|
|
9715
|
+
fs2.mkdirSync(scaffoldPath, { recursive: true });
|
|
9716
|
+
}
|
|
9717
|
+
for (const name of COPY_FILES) {
|
|
9718
|
+
const src = path3.join(PACKAGE_ROOT, name);
|
|
9719
|
+
const dest = path3.join(scaffoldPath, name);
|
|
9720
|
+
ensureRemoved(dest);
|
|
9721
|
+
copyRecursive(src, dest);
|
|
9722
|
+
}
|
|
9723
|
+
generateNextConfig(scaffoldPath);
|
|
9724
|
+
const contentLink = path3.join(scaffoldPath, "content");
|
|
9725
|
+
ensureRemoved(contentLink);
|
|
9726
|
+
fs2.symlinkSync(path3.resolve(contentDir), contentLink);
|
|
9727
|
+
ensureDeps();
|
|
9728
|
+
console.log(source_default.gray(`Scaffold: ${scaffoldPath}`));
|
|
9729
|
+
return scaffoldPath;
|
|
9730
|
+
}
|
|
9585
9731
|
// src/cli/commands/init.ts
|
|
9586
9732
|
function createConfig() {
|
|
9587
9733
|
return {
|
|
@@ -9591,6 +9737,27 @@ function createConfig() {
|
|
|
9591
9737
|
search: { enabled: true, placeholder: "Search documentation..." }
|
|
9592
9738
|
};
|
|
9593
9739
|
}
|
|
9740
|
+
function createPackageJson2(name) {
|
|
9741
|
+
return {
|
|
9742
|
+
name,
|
|
9743
|
+
private: true,
|
|
9744
|
+
scripts: {
|
|
9745
|
+
dev: "chronicle dev",
|
|
9746
|
+
build: "chronicle build",
|
|
9747
|
+
start: "chronicle start"
|
|
9748
|
+
},
|
|
9749
|
+
dependencies: {
|
|
9750
|
+
"@raystack/chronicle": "latest"
|
|
9751
|
+
},
|
|
9752
|
+
devDependencies: {
|
|
9753
|
+
"@raystack/tools-config": "0.56.0",
|
|
9754
|
+
"openapi-types": "^12.1.3",
|
|
9755
|
+
typescript: "5.9.3",
|
|
9756
|
+
"@types/react": "^19.2.10",
|
|
9757
|
+
"@types/node": "^25.1.0"
|
|
9758
|
+
}
|
|
9759
|
+
};
|
|
9760
|
+
}
|
|
9594
9761
|
var sampleMdx = `---
|
|
9595
9762
|
title: Welcome
|
|
9596
9763
|
description: Getting started with your documentation
|
|
@@ -9601,90 +9768,82 @@ order: 1
|
|
|
9601
9768
|
|
|
9602
9769
|
This is your documentation home page.
|
|
9603
9770
|
`;
|
|
9604
|
-
var initCommand = new Command("init").description("Initialize a new Chronicle project").option("-
|
|
9605
|
-
const
|
|
9606
|
-
|
|
9607
|
-
|
|
9771
|
+
var initCommand = new Command("init").description("Initialize a new Chronicle project").option("-c, --content <path>", "Content directory name", "content").action((options) => {
|
|
9772
|
+
const projectDir = process.cwd();
|
|
9773
|
+
const dirName = path4.basename(projectDir) || "docs";
|
|
9774
|
+
const contentDir = path4.join(projectDir, options.content);
|
|
9775
|
+
if (!fs3.existsSync(contentDir)) {
|
|
9776
|
+
fs3.mkdirSync(contentDir, { recursive: true });
|
|
9608
9777
|
console.log(source_default.green("✓"), "Created", contentDir);
|
|
9609
9778
|
}
|
|
9610
|
-
const
|
|
9611
|
-
if (!
|
|
9612
|
-
|
|
9779
|
+
const packageJsonPath = path4.join(projectDir, "package.json");
|
|
9780
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
9781
|
+
fs3.writeFileSync(packageJsonPath, JSON.stringify(createPackageJson2(dirName), null, 2) + `
|
|
9782
|
+
`);
|
|
9783
|
+
console.log(source_default.green("✓"), "Created", packageJsonPath);
|
|
9784
|
+
} else {
|
|
9785
|
+
console.log(source_default.yellow("⚠"), packageJsonPath, "already exists");
|
|
9786
|
+
}
|
|
9787
|
+
const configPath = path4.join(projectDir, "chronicle.yaml");
|
|
9788
|
+
if (!fs3.existsSync(configPath)) {
|
|
9789
|
+
fs3.writeFileSync(configPath, $stringify(createConfig()));
|
|
9613
9790
|
console.log(source_default.green("✓"), "Created", configPath);
|
|
9614
9791
|
} else {
|
|
9615
9792
|
console.log(source_default.yellow("⚠"), configPath, "already exists");
|
|
9616
9793
|
}
|
|
9617
|
-
const
|
|
9618
|
-
if (
|
|
9619
|
-
|
|
9794
|
+
const contentFiles = fs3.readdirSync(contentDir);
|
|
9795
|
+
if (contentFiles.length === 0) {
|
|
9796
|
+
const indexPath = path4.join(contentDir, "index.mdx");
|
|
9797
|
+
fs3.writeFileSync(indexPath, sampleMdx);
|
|
9620
9798
|
console.log(source_default.green("✓"), "Created", indexPath);
|
|
9621
9799
|
}
|
|
9800
|
+
const gitignorePath = path4.join(projectDir, ".gitignore");
|
|
9801
|
+
const chronicleEntry = ".chronicle";
|
|
9802
|
+
if (fs3.existsSync(gitignorePath)) {
|
|
9803
|
+
const existing = fs3.readFileSync(gitignorePath, "utf-8");
|
|
9804
|
+
if (!existing.includes(chronicleEntry)) {
|
|
9805
|
+
fs3.appendFileSync(gitignorePath, `
|
|
9806
|
+
${chronicleEntry}
|
|
9807
|
+
`);
|
|
9808
|
+
console.log(source_default.green("✓"), "Added .chronicle to .gitignore");
|
|
9809
|
+
}
|
|
9810
|
+
} else {
|
|
9811
|
+
fs3.writeFileSync(gitignorePath, `${chronicleEntry}
|
|
9812
|
+
`);
|
|
9813
|
+
console.log(source_default.green("✓"), "Created .gitignore with .chronicle");
|
|
9814
|
+
}
|
|
9815
|
+
const pm = detectPackageManager();
|
|
9816
|
+
console.log(source_default.cyan(`
|
|
9817
|
+
Installing dependencies with ${pm}...`));
|
|
9818
|
+
execSync2(`${pm} install`, { cwd: projectDir, stdio: "inherit" });
|
|
9819
|
+
loadCLIConfig(contentDir);
|
|
9820
|
+
scaffoldDir(contentDir);
|
|
9821
|
+
const runCmd = pm === "npm" ? "npx" : pm === "bun" ? "bunx" : `${pm} dlx`;
|
|
9622
9822
|
console.log(source_default.green(`
|
|
9623
9823
|
✓ Chronicle initialized!`));
|
|
9624
9824
|
console.log(`
|
|
9625
|
-
Run`, source_default.cyan(
|
|
9825
|
+
Run`, source_default.cyan(`${runCmd} chronicle dev`), "to start development server");
|
|
9626
9826
|
});
|
|
9627
9827
|
|
|
9628
9828
|
// src/cli/commands/dev.ts
|
|
9629
9829
|
import { spawn } from "child_process";
|
|
9630
|
-
import
|
|
9631
|
-
import
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
import path2 from "path";
|
|
9637
|
-
function resolveContentDir(contentFlag) {
|
|
9638
|
-
if (contentFlag)
|
|
9639
|
-
return path2.resolve(contentFlag);
|
|
9640
|
-
if (process.env.CHRONICLE_CONTENT_DIR)
|
|
9641
|
-
return path2.resolve(process.env.CHRONICLE_CONTENT_DIR);
|
|
9642
|
-
return process.cwd();
|
|
9643
|
-
}
|
|
9644
|
-
function resolveConfigPath(contentDir) {
|
|
9645
|
-
const cwdPath = path2.join(process.cwd(), "chronicle.yaml");
|
|
9646
|
-
if (fs2.existsSync(cwdPath))
|
|
9647
|
-
return cwdPath;
|
|
9648
|
-
const contentPath = path2.join(contentDir, "chronicle.yaml");
|
|
9649
|
-
if (fs2.existsSync(contentPath))
|
|
9650
|
-
return contentPath;
|
|
9651
|
-
return null;
|
|
9652
|
-
}
|
|
9653
|
-
function loadCLIConfig(contentDir) {
|
|
9654
|
-
const configPath = resolveConfigPath(contentDir);
|
|
9655
|
-
if (!configPath) {
|
|
9656
|
-
console.log(source_default.red("Error: chronicle.yaml not found in"), process.cwd(), "or", contentDir);
|
|
9657
|
-
console.log(source_default.gray(`Run 'chronicle init' to create one`));
|
|
9830
|
+
import path5 from "path";
|
|
9831
|
+
import fs4 from "fs";
|
|
9832
|
+
var devCommand = new Command("dev").description("Start development server").option("-p, --port <port>", "Port number", "3000").action((options) => {
|
|
9833
|
+
const scaffoldPath = path5.join(process.cwd(), ".chronicle");
|
|
9834
|
+
if (!fs4.existsSync(scaffoldPath)) {
|
|
9835
|
+
console.log(source_default.red("Error: .chronicle/ not found. Run"), source_default.cyan("chronicle init"), source_default.red("first."));
|
|
9658
9836
|
process.exit(1);
|
|
9659
9837
|
}
|
|
9660
|
-
const
|
|
9661
|
-
return {
|
|
9662
|
-
config,
|
|
9663
|
-
configPath,
|
|
9664
|
-
contentDir
|
|
9665
|
-
};
|
|
9666
|
-
}
|
|
9667
|
-
// src/cli/utils/process.ts
|
|
9668
|
-
function attachLifecycleHandlers(child) {
|
|
9669
|
-
child.on("close", (code) => process.exit(code ?? 0));
|
|
9670
|
-
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
9671
|
-
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
9672
|
-
}
|
|
9673
|
-
// src/cli/commands/dev.ts
|
|
9674
|
-
var require2 = createRequire2(import.meta.url);
|
|
9675
|
-
var PACKAGE_ROOT = path3.resolve(path3.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9676
|
-
var nextCli = require2.resolve("next/dist/bin/next");
|
|
9677
|
-
var devCommand = new Command("dev").description("Start development server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").action((options) => {
|
|
9678
|
-
const contentDir = resolveContentDir(options.content);
|
|
9679
|
-
loadCLIConfig(contentDir);
|
|
9838
|
+
const nextCli = resolveNextCli();
|
|
9680
9839
|
console.log(source_default.cyan("Starting dev server..."));
|
|
9681
|
-
console.log(source_default.gray(`Content: ${contentDir}`));
|
|
9682
9840
|
const child = spawn(process.execPath, [nextCli, "dev", "-p", options.port], {
|
|
9683
9841
|
stdio: "inherit",
|
|
9684
|
-
cwd:
|
|
9842
|
+
cwd: scaffoldPath,
|
|
9685
9843
|
env: {
|
|
9686
9844
|
...process.env,
|
|
9687
|
-
|
|
9845
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
9846
|
+
CHRONICLE_CONTENT_DIR: "./content"
|
|
9688
9847
|
}
|
|
9689
9848
|
});
|
|
9690
9849
|
attachLifecycleHandlers(child);
|
|
@@ -9692,23 +9851,23 @@ var devCommand = new Command("dev").description("Start development server").opti
|
|
|
9692
9851
|
|
|
9693
9852
|
// src/cli/commands/build.ts
|
|
9694
9853
|
import { spawn as spawn2 } from "child_process";
|
|
9695
|
-
import
|
|
9696
|
-
import
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9854
|
+
import path6 from "path";
|
|
9855
|
+
import fs5 from "fs";
|
|
9856
|
+
var buildCommand = new Command("build").description("Build for production").action(() => {
|
|
9857
|
+
const scaffoldPath = path6.join(process.cwd(), ".chronicle");
|
|
9858
|
+
if (!fs5.existsSync(scaffoldPath)) {
|
|
9859
|
+
console.log(source_default.red("Error: .chronicle/ not found. Run"), source_default.cyan("chronicle init"), source_default.red("first."));
|
|
9860
|
+
process.exit(1);
|
|
9861
|
+
}
|
|
9862
|
+
const nextCli = resolveNextCli();
|
|
9704
9863
|
console.log(source_default.cyan("Building for production..."));
|
|
9705
|
-
|
|
9706
|
-
const child = spawn2(process.execPath, [nextCli2, "build"], {
|
|
9864
|
+
const child = spawn2(process.execPath, [nextCli, "build"], {
|
|
9707
9865
|
stdio: "inherit",
|
|
9708
|
-
cwd:
|
|
9866
|
+
cwd: scaffoldPath,
|
|
9709
9867
|
env: {
|
|
9710
9868
|
...process.env,
|
|
9711
|
-
|
|
9869
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
9870
|
+
CHRONICLE_CONTENT_DIR: "./content"
|
|
9712
9871
|
}
|
|
9713
9872
|
});
|
|
9714
9873
|
attachLifecycleHandlers(child);
|
|
@@ -9716,23 +9875,23 @@ var buildCommand = new Command("build").description("Build for production").opti
|
|
|
9716
9875
|
|
|
9717
9876
|
// src/cli/commands/start.ts
|
|
9718
9877
|
import { spawn as spawn3 } from "child_process";
|
|
9719
|
-
import
|
|
9720
|
-
import
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9878
|
+
import path7 from "path";
|
|
9879
|
+
import fs6 from "fs";
|
|
9880
|
+
var startCommand = new Command("start").description("Start production server").option("-p, --port <port>", "Port number", "3000").action((options) => {
|
|
9881
|
+
const scaffoldPath = path7.join(process.cwd(), ".chronicle");
|
|
9882
|
+
if (!fs6.existsSync(scaffoldPath)) {
|
|
9883
|
+
console.log(source_default.red("Error: .chronicle/ not found. Run"), source_default.cyan("chronicle init"), source_default.red("first."));
|
|
9884
|
+
process.exit(1);
|
|
9885
|
+
}
|
|
9886
|
+
const nextCli = resolveNextCli();
|
|
9728
9887
|
console.log(source_default.cyan("Starting production server..."));
|
|
9729
|
-
|
|
9730
|
-
const child = spawn3(process.execPath, [nextCli3, "start", "-p", options.port], {
|
|
9888
|
+
const child = spawn3(process.execPath, [nextCli, "start", "-p", options.port], {
|
|
9731
9889
|
stdio: "inherit",
|
|
9732
|
-
cwd:
|
|
9890
|
+
cwd: scaffoldPath,
|
|
9733
9891
|
env: {
|
|
9734
9892
|
...process.env,
|
|
9735
|
-
|
|
9893
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
9894
|
+
CHRONICLE_CONTENT_DIR: "./content"
|
|
9736
9895
|
}
|
|
9737
9896
|
});
|
|
9738
9897
|
attachLifecycleHandlers(child);
|
|
@@ -9740,24 +9899,24 @@ var startCommand = new Command("start").description("Start production server").o
|
|
|
9740
9899
|
|
|
9741
9900
|
// src/cli/commands/serve.ts
|
|
9742
9901
|
import { spawn as spawn4 } from "child_process";
|
|
9743
|
-
import
|
|
9744
|
-
import
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9902
|
+
import path8 from "path";
|
|
9903
|
+
import fs7 from "fs";
|
|
9904
|
+
var serveCommand = new Command("serve").description("Build and start production server").option("-p, --port <port>", "Port number", "3000").action((options) => {
|
|
9905
|
+
const scaffoldPath = path8.join(process.cwd(), ".chronicle");
|
|
9906
|
+
if (!fs7.existsSync(scaffoldPath)) {
|
|
9907
|
+
console.log(source_default.red("Error: .chronicle/ not found. Run"), source_default.cyan("chronicle init"), source_default.red("first."));
|
|
9908
|
+
process.exit(1);
|
|
9909
|
+
}
|
|
9910
|
+
const nextCli = resolveNextCli();
|
|
9752
9911
|
const env2 = {
|
|
9753
9912
|
...process.env,
|
|
9754
|
-
|
|
9913
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
9914
|
+
CHRONICLE_CONTENT_DIR: "./content"
|
|
9755
9915
|
};
|
|
9756
9916
|
console.log(source_default.cyan("Building for production..."));
|
|
9757
|
-
|
|
9758
|
-
const buildChild = spawn4(process.execPath, [nextCli4, "build"], {
|
|
9917
|
+
const buildChild = spawn4(process.execPath, [nextCli, "build"], {
|
|
9759
9918
|
stdio: "inherit",
|
|
9760
|
-
cwd:
|
|
9919
|
+
cwd: scaffoldPath,
|
|
9761
9920
|
env: env2
|
|
9762
9921
|
});
|
|
9763
9922
|
process.once("SIGINT", () => buildChild.kill("SIGINT"));
|
|
@@ -9768,9 +9927,9 @@ var serveCommand = new Command("serve").description("Build and start production
|
|
|
9768
9927
|
process.exit(code ?? 1);
|
|
9769
9928
|
}
|
|
9770
9929
|
console.log(source_default.cyan("Starting production server..."));
|
|
9771
|
-
const startChild = spawn4(process.execPath, [
|
|
9930
|
+
const startChild = spawn4(process.execPath, [nextCli, "start", "-p", options.port], {
|
|
9772
9931
|
stdio: "inherit",
|
|
9773
|
-
cwd:
|
|
9932
|
+
cwd: scaffoldPath,
|
|
9774
9933
|
env: env2
|
|
9775
9934
|
});
|
|
9776
9935
|
attachLifecycleHandlers(startChild);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raystack/chronicle",
|
|
3
|
-
"version": "0.1.0-canary.
|
|
3
|
+
"version": "0.1.0-canary.f94fdd7",
|
|
4
4
|
"description": "Config-driven documentation framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"src",
|
|
11
11
|
"templates",
|
|
12
12
|
"next.config.mjs",
|
|
13
|
-
"source.config.ts"
|
|
13
|
+
"source.config.ts",
|
|
14
|
+
"tsconfig.json"
|
|
14
15
|
],
|
|
15
16
|
"bin": {
|
|
16
17
|
"chronicle": "./bin/chronicle.js"
|
|
@@ -27,7 +28,6 @@
|
|
|
27
28
|
"@types/react": "^19.2.10",
|
|
28
29
|
"@types/react-dom": "^19.2.3",
|
|
29
30
|
"@types/semver": "^7.7.1",
|
|
30
|
-
"openapi-types": "^12.1.3",
|
|
31
31
|
"semver": "^7.7.4",
|
|
32
32
|
"typescript": "5.9.3"
|
|
33
33
|
},
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"slugify": "^1.6.6",
|
|
57
57
|
"unified": "^11.0.5",
|
|
58
58
|
"unist-util-visit": "^5.1.0",
|
|
59
|
+
"openapi-types": "^12.1.3",
|
|
59
60
|
"yaml": "^2.8.2",
|
|
60
61
|
"zod": "^4.3.6"
|
|
61
62
|
}
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
import { spawn } from 'child_process'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
5
|
-
import { createRequire } from 'module'
|
|
4
|
+
import fs from 'fs'
|
|
6
5
|
import chalk from 'chalk'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
6
|
+
import { attachLifecycleHandlers, resolveNextCli } from '@/cli/utils'
|
|
12
7
|
|
|
13
8
|
export const buildCommand = new Command('build')
|
|
14
9
|
.description('Build for production')
|
|
15
|
-
.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
.action(() => {
|
|
11
|
+
const scaffoldPath = path.join(process.cwd(), '.chronicle')
|
|
12
|
+
if (!fs.existsSync(scaffoldPath)) {
|
|
13
|
+
console.log(chalk.red('Error: .chronicle/ not found. Run'), chalk.cyan('chronicle init'), chalk.red('first.'))
|
|
14
|
+
process.exit(1)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const nextCli = resolveNextCli()
|
|
19
18
|
|
|
20
19
|
console.log(chalk.cyan('Building for production...'))
|
|
21
|
-
console.log(chalk.gray(`Content: ${contentDir}`))
|
|
22
20
|
|
|
23
21
|
const child = spawn(process.execPath, [nextCli, 'build'], {
|
|
24
22
|
stdio: 'inherit',
|
|
25
|
-
cwd:
|
|
23
|
+
cwd: scaffoldPath,
|
|
26
24
|
env: {
|
|
27
25
|
...process.env,
|
|
28
|
-
|
|
26
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
27
|
+
CHRONICLE_CONTENT_DIR: './content',
|
|
29
28
|
},
|
|
30
29
|
})
|
|
31
30
|
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
import { spawn } from 'child_process'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
5
|
-
import { createRequire } from 'module'
|
|
4
|
+
import fs from 'fs'
|
|
6
5
|
import chalk from 'chalk'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
6
|
+
import { attachLifecycleHandlers, resolveNextCli } from '@/cli/utils'
|
|
12
7
|
|
|
13
8
|
export const devCommand = new Command('dev')
|
|
14
9
|
.description('Start development server')
|
|
15
10
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
16
|
-
.option('-c, --content <path>', 'Content directory')
|
|
17
11
|
.action((options) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
12
|
+
const scaffoldPath = path.join(process.cwd(), '.chronicle')
|
|
13
|
+
if (!fs.existsSync(scaffoldPath)) {
|
|
14
|
+
console.log(chalk.red('Error: .chronicle/ not found. Run'), chalk.cyan('chronicle init'), chalk.red('first.'))
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const nextCli = resolveNextCli()
|
|
20
19
|
|
|
21
20
|
console.log(chalk.cyan('Starting dev server...'))
|
|
22
|
-
console.log(chalk.gray(`Content: ${contentDir}`))
|
|
23
21
|
|
|
24
22
|
const child = spawn(process.execPath, [nextCli, 'dev', '-p', options.port], {
|
|
25
23
|
stdio: 'inherit',
|
|
26
|
-
cwd:
|
|
24
|
+
cwd: scaffoldPath,
|
|
27
25
|
env: {
|
|
28
26
|
...process.env,
|
|
29
|
-
|
|
27
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
28
|
+
CHRONICLE_CONTENT_DIR: './content',
|
|
30
29
|
},
|
|
31
30
|
})
|
|
32
31
|
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
+
import { execSync } from 'child_process'
|
|
2
3
|
import fs from 'fs'
|
|
3
4
|
import path from 'path'
|
|
4
5
|
import chalk from 'chalk'
|
|
5
6
|
import { stringify } from 'yaml'
|
|
6
7
|
import type { ChronicleConfig } from '@/types'
|
|
8
|
+
import { loadCLIConfig, scaffoldDir, detectPackageManager } from '@/cli/utils'
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
function createConfig(): ChronicleConfig {
|
|
9
12
|
return {
|
|
@@ -14,6 +17,28 @@ function createConfig(): ChronicleConfig {
|
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
function createPackageJson(name: string): Record<string, unknown> {
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
private: true,
|
|
24
|
+
scripts: {
|
|
25
|
+
dev: 'chronicle dev',
|
|
26
|
+
build: 'chronicle build',
|
|
27
|
+
start: 'chronicle start',
|
|
28
|
+
},
|
|
29
|
+
dependencies: {
|
|
30
|
+
'@raystack/chronicle': 'latest',
|
|
31
|
+
},
|
|
32
|
+
devDependencies: {
|
|
33
|
+
'@raystack/tools-config': '0.56.0',
|
|
34
|
+
'openapi-types': '^12.1.3',
|
|
35
|
+
typescript: '5.9.3',
|
|
36
|
+
'@types/react': '^19.2.10',
|
|
37
|
+
'@types/node': '^25.1.0',
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
17
42
|
const sampleMdx = `---
|
|
18
43
|
title: Welcome
|
|
19
44
|
description: Getting started with your documentation
|
|
@@ -27,18 +52,29 @@ This is your documentation home page.
|
|
|
27
52
|
|
|
28
53
|
export const initCommand = new Command('init')
|
|
29
54
|
.description('Initialize a new Chronicle project')
|
|
30
|
-
.option('-
|
|
55
|
+
.option('-c, --content <path>', 'Content directory name', 'content')
|
|
31
56
|
.action((options) => {
|
|
32
|
-
const
|
|
57
|
+
const projectDir = process.cwd()
|
|
58
|
+
const dirName = path.basename(projectDir) || 'docs'
|
|
59
|
+
const contentDir = path.join(projectDir, options.content)
|
|
33
60
|
|
|
34
|
-
// Create content directory
|
|
61
|
+
// Create content directory if it doesn't exist
|
|
35
62
|
if (!fs.existsSync(contentDir)) {
|
|
36
63
|
fs.mkdirSync(contentDir, { recursive: true })
|
|
37
64
|
console.log(chalk.green('✓'), 'Created', contentDir)
|
|
38
65
|
}
|
|
39
66
|
|
|
40
|
-
// Create
|
|
41
|
-
const
|
|
67
|
+
// Create package.json in project root
|
|
68
|
+
const packageJsonPath = path.join(projectDir, 'package.json')
|
|
69
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
70
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(createPackageJson(dirName), null, 2) + '\n')
|
|
71
|
+
console.log(chalk.green('✓'), 'Created', packageJsonPath)
|
|
72
|
+
} else {
|
|
73
|
+
console.log(chalk.yellow('⚠'), packageJsonPath, 'already exists')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Create chronicle.yaml in project root
|
|
77
|
+
const configPath = path.join(projectDir, 'chronicle.yaml')
|
|
42
78
|
if (!fs.existsSync(configPath)) {
|
|
43
79
|
fs.writeFileSync(configPath, stringify(createConfig()))
|
|
44
80
|
console.log(chalk.green('✓'), 'Created', configPath)
|
|
@@ -46,13 +82,38 @@ export const initCommand = new Command('init')
|
|
|
46
82
|
console.log(chalk.yellow('⚠'), configPath, 'already exists')
|
|
47
83
|
}
|
|
48
84
|
|
|
49
|
-
// Create sample index.mdx
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
85
|
+
// Create sample index.mdx only if content dir is empty
|
|
86
|
+
const contentFiles = fs.readdirSync(contentDir)
|
|
87
|
+
if (contentFiles.length === 0) {
|
|
88
|
+
const indexPath = path.join(contentDir, 'index.mdx')
|
|
52
89
|
fs.writeFileSync(indexPath, sampleMdx)
|
|
53
90
|
console.log(chalk.green('✓'), 'Created', indexPath)
|
|
54
91
|
}
|
|
55
92
|
|
|
93
|
+
// Add .chronicle to .gitignore
|
|
94
|
+
const gitignorePath = path.join(projectDir, '.gitignore')
|
|
95
|
+
const chronicleEntry = '.chronicle'
|
|
96
|
+
if (fs.existsSync(gitignorePath)) {
|
|
97
|
+
const existing = fs.readFileSync(gitignorePath, 'utf-8')
|
|
98
|
+
if (!existing.includes(chronicleEntry)) {
|
|
99
|
+
fs.appendFileSync(gitignorePath, `\n${chronicleEntry}\n`)
|
|
100
|
+
console.log(chalk.green('✓'), 'Added .chronicle to .gitignore')
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
fs.writeFileSync(gitignorePath, `${chronicleEntry}\n`)
|
|
104
|
+
console.log(chalk.green('✓'), 'Created .gitignore with .chronicle')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Install dependencies
|
|
108
|
+
const pm = detectPackageManager()
|
|
109
|
+
console.log(chalk.cyan(`\nInstalling dependencies with ${pm}...`))
|
|
110
|
+
execSync(`${pm} install`, { cwd: projectDir, stdio: 'inherit' })
|
|
111
|
+
|
|
112
|
+
// Scaffold .chronicle/ directory
|
|
113
|
+
loadCLIConfig(contentDir)
|
|
114
|
+
scaffoldDir(contentDir)
|
|
115
|
+
|
|
116
|
+
const runCmd = pm === 'npm' ? 'npx' : pm === 'bun' ? 'bunx' : `${pm} dlx`
|
|
56
117
|
console.log(chalk.green('\n✓ Chronicle initialized!'))
|
|
57
|
-
console.log('\nRun', chalk.cyan(
|
|
118
|
+
console.log('\nRun', chalk.cyan(`${runCmd} chronicle dev`), 'to start development server')
|
|
58
119
|
})
|
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
import { spawn } from 'child_process'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
5
|
-
import { createRequire } from 'module'
|
|
4
|
+
import fs from 'fs'
|
|
6
5
|
import chalk from 'chalk'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
6
|
+
import { attachLifecycleHandlers, resolveNextCli } from '@/cli/utils'
|
|
12
7
|
|
|
13
8
|
export const serveCommand = new Command('serve')
|
|
14
9
|
.description('Build and start production server')
|
|
15
10
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
16
|
-
.option('-c, --content <path>', 'Content directory')
|
|
17
11
|
.action((options) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
12
|
+
const scaffoldPath = path.join(process.cwd(), '.chronicle')
|
|
13
|
+
if (!fs.existsSync(scaffoldPath)) {
|
|
14
|
+
console.log(chalk.red('Error: .chronicle/ not found. Run'), chalk.cyan('chronicle init'), chalk.red('first.'))
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const nextCli = resolveNextCli()
|
|
20
19
|
|
|
21
20
|
const env = {
|
|
22
21
|
...process.env,
|
|
23
|
-
|
|
22
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
23
|
+
CHRONICLE_CONTENT_DIR: './content',
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
console.log(chalk.cyan('Building for production...'))
|
|
27
|
-
console.log(chalk.gray(`Content: ${contentDir}`))
|
|
28
27
|
|
|
29
28
|
const buildChild = spawn(process.execPath, [nextCli, 'build'], {
|
|
30
29
|
stdio: 'inherit',
|
|
31
|
-
cwd:
|
|
30
|
+
cwd: scaffoldPath,
|
|
32
31
|
env,
|
|
33
32
|
})
|
|
34
33
|
|
|
@@ -45,7 +44,7 @@ export const serveCommand = new Command('serve')
|
|
|
45
44
|
|
|
46
45
|
const startChild = spawn(process.execPath, [nextCli, 'start', '-p', options.port], {
|
|
47
46
|
stdio: 'inherit',
|
|
48
|
-
cwd:
|
|
47
|
+
cwd: scaffoldPath,
|
|
49
48
|
env,
|
|
50
49
|
})
|
|
51
50
|
|
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
import { spawn } from 'child_process'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
5
|
-
import { createRequire } from 'module'
|
|
4
|
+
import fs from 'fs'
|
|
6
5
|
import chalk from 'chalk'
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
6
|
+
import { attachLifecycleHandlers, resolveNextCli } from '@/cli/utils'
|
|
12
7
|
|
|
13
8
|
export const startCommand = new Command('start')
|
|
14
9
|
.description('Start production server')
|
|
15
10
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
16
|
-
.option('-c, --content <path>', 'Content directory')
|
|
17
11
|
.action((options) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
12
|
+
const scaffoldPath = path.join(process.cwd(), '.chronicle')
|
|
13
|
+
if (!fs.existsSync(scaffoldPath)) {
|
|
14
|
+
console.log(chalk.red('Error: .chronicle/ not found. Run'), chalk.cyan('chronicle init'), chalk.red('first.'))
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const nextCli = resolveNextCli()
|
|
20
19
|
|
|
21
20
|
console.log(chalk.cyan('Starting production server...'))
|
|
22
|
-
console.log(chalk.gray(`Content: ${contentDir}`))
|
|
23
21
|
|
|
24
22
|
const child = spawn(process.execPath, [nextCli, 'start', '-p', options.port], {
|
|
25
23
|
stdio: 'inherit',
|
|
26
|
-
cwd:
|
|
24
|
+
cwd: scaffoldPath,
|
|
27
25
|
env: {
|
|
28
26
|
...process.env,
|
|
29
|
-
|
|
27
|
+
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
28
|
+
CHRONICLE_CONTENT_DIR: './content',
|
|
30
29
|
},
|
|
31
30
|
})
|
|
32
31
|
|
package/src/cli/utils/config.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface CLIConfig {
|
|
|
13
13
|
export function resolveContentDir(contentFlag?: string): string {
|
|
14
14
|
if (contentFlag) return path.resolve(contentFlag)
|
|
15
15
|
if (process.env.CHRONICLE_CONTENT_DIR) return path.resolve(process.env.CHRONICLE_CONTENT_DIR)
|
|
16
|
-
return
|
|
16
|
+
return path.resolve('content')
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function resolveConfigPath(contentDir: string): string | null {
|
package/src/cli/utils/index.ts
CHANGED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { execSync } from 'child_process'
|
|
2
|
+
import { createRequire } from 'module'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import chalk from 'chalk'
|
|
6
|
+
import { PACKAGE_ROOT } from './resolve'
|
|
7
|
+
|
|
8
|
+
const COPY_FILES = ['src', 'source.config.ts', 'tsconfig.json']
|
|
9
|
+
|
|
10
|
+
function copyRecursive(src: string, dest: string) {
|
|
11
|
+
const stat = fs.statSync(src)
|
|
12
|
+
if (stat.isDirectory()) {
|
|
13
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
14
|
+
for (const entry of fs.readdirSync(src)) {
|
|
15
|
+
copyRecursive(path.join(src, entry), path.join(dest, entry))
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
fs.copyFileSync(src, dest)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function ensureRemoved(targetPath: string) {
|
|
23
|
+
try {
|
|
24
|
+
fs.lstatSync(targetPath)
|
|
25
|
+
fs.rmSync(targetPath, { recursive: true, force: true })
|
|
26
|
+
} catch {
|
|
27
|
+
// nothing exists, proceed
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function detectPackageManager(): string {
|
|
32
|
+
if (process.env.npm_config_user_agent) {
|
|
33
|
+
return process.env.npm_config_user_agent.split('/')[0]
|
|
34
|
+
}
|
|
35
|
+
const cwd = process.cwd()
|
|
36
|
+
if (fs.existsSync(path.join(cwd, 'bun.lock')) || fs.existsSync(path.join(cwd, 'bun.lockb'))) return 'bun'
|
|
37
|
+
if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm'
|
|
38
|
+
if (fs.existsSync(path.join(cwd, 'yarn.lock'))) return 'yarn'
|
|
39
|
+
return 'npm'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function generateNextConfig(scaffoldPath: string) {
|
|
43
|
+
const config = `import { createMDX } from 'fumadocs-mdx/next'
|
|
44
|
+
|
|
45
|
+
const withMDX = createMDX()
|
|
46
|
+
|
|
47
|
+
/** @type {import('next').NextConfig} */
|
|
48
|
+
const nextConfig = {
|
|
49
|
+
reactStrictMode: true,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default withMDX(nextConfig)
|
|
53
|
+
`
|
|
54
|
+
fs.writeFileSync(path.join(scaffoldPath, 'next.config.mjs'), config)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function createPackageJson(): Record<string, unknown> {
|
|
58
|
+
return {
|
|
59
|
+
name: 'chronicle-docs',
|
|
60
|
+
private: true,
|
|
61
|
+
dependencies: {
|
|
62
|
+
'@raystack/chronicle': 'latest',
|
|
63
|
+
},
|
|
64
|
+
devDependencies: {
|
|
65
|
+
'@raystack/tools-config': '0.56.0',
|
|
66
|
+
'openapi-types': '^12.1.3',
|
|
67
|
+
typescript: '5.9.3',
|
|
68
|
+
'@types/react': '^19.2.10',
|
|
69
|
+
'@types/node': '^25.1.0',
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function ensureDeps() {
|
|
75
|
+
const cwd = process.cwd()
|
|
76
|
+
const cwdPkgJson = path.join(cwd, 'package.json')
|
|
77
|
+
const cwdNodeModules = path.join(cwd, 'node_modules')
|
|
78
|
+
|
|
79
|
+
if (fs.existsSync(cwdPkgJson) && fs.existsSync(cwdNodeModules)) {
|
|
80
|
+
// Case 1: existing project with deps installed
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Case 2: no package.json — create in cwd and install
|
|
85
|
+
if (!fs.existsSync(cwdPkgJson)) {
|
|
86
|
+
fs.writeFileSync(cwdPkgJson, JSON.stringify(createPackageJson(), null, 2) + '\n')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!fs.existsSync(cwdNodeModules)) {
|
|
90
|
+
const pm = detectPackageManager()
|
|
91
|
+
console.log(chalk.cyan(`Installing dependencies with ${pm}...`))
|
|
92
|
+
execSync(`${pm} install`, { cwd, stdio: 'inherit' })
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function resolveNextCli(): string {
|
|
97
|
+
const cwdRequire = createRequire(path.join(process.cwd(), 'package.json'))
|
|
98
|
+
return cwdRequire.resolve('next/dist/bin/next')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function scaffoldDir(contentDir: string): string {
|
|
102
|
+
const scaffoldPath = path.join(process.cwd(), '.chronicle')
|
|
103
|
+
|
|
104
|
+
// Create .chronicle/ if not exists
|
|
105
|
+
if (!fs.existsSync(scaffoldPath)) {
|
|
106
|
+
fs.mkdirSync(scaffoldPath, { recursive: true })
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Copy package files
|
|
110
|
+
for (const name of COPY_FILES) {
|
|
111
|
+
const src = path.join(PACKAGE_ROOT, name)
|
|
112
|
+
const dest = path.join(scaffoldPath, name)
|
|
113
|
+
ensureRemoved(dest)
|
|
114
|
+
copyRecursive(src, dest)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Generate next.config.mjs
|
|
118
|
+
generateNextConfig(scaffoldPath)
|
|
119
|
+
|
|
120
|
+
// Symlink content dir
|
|
121
|
+
const contentLink = path.join(scaffoldPath, 'content')
|
|
122
|
+
ensureRemoved(contentLink)
|
|
123
|
+
fs.symlinkSync(path.resolve(contentDir), contentLink)
|
|
124
|
+
|
|
125
|
+
// Ensure dependencies are available
|
|
126
|
+
ensureDeps()
|
|
127
|
+
|
|
128
|
+
console.log(chalk.gray(`Scaffold: ${scaffoldPath}`))
|
|
129
|
+
|
|
130
|
+
return scaffoldPath
|
|
131
|
+
}
|
package/src/lib/config.ts
CHANGED
|
@@ -12,8 +12,16 @@ const defaultConfig: ChronicleConfig = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function resolveConfigPath(): string | null {
|
|
15
|
+
// Check project root via env var
|
|
16
|
+
const projectRoot = process.env.CHRONICLE_PROJECT_ROOT
|
|
17
|
+
if (projectRoot) {
|
|
18
|
+
const rootPath = path.join(projectRoot, CONFIG_FILE)
|
|
19
|
+
if (fs.existsSync(rootPath)) return rootPath
|
|
20
|
+
}
|
|
21
|
+
// Check cwd
|
|
15
22
|
const cwdPath = path.join(process.cwd(), CONFIG_FILE)
|
|
16
23
|
if (fs.existsSync(cwdPath)) return cwdPath
|
|
24
|
+
// Check content dir
|
|
17
25
|
const contentDir = process.env.CHRONICLE_CONTENT_DIR
|
|
18
26
|
if (contentDir) {
|
|
19
27
|
const contentPath = path.join(contentDir, CONFIG_FILE)
|
package/src/lib/source.ts
CHANGED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"composite": false,
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"forceConsistentCasingInFileNames": true,
|
|
8
|
+
"inlineSources": false,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"noUnusedLocals": false,
|
|
11
|
+
"noUnusedParameters": false,
|
|
12
|
+
"preserveWatchOutput": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
"module": "ESNext",
|
|
17
|
+
"target": "es6",
|
|
18
|
+
"outDir": "dist",
|
|
19
|
+
"rootDir": ".",
|
|
20
|
+
"baseUrl": ".",
|
|
21
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
22
|
+
"moduleResolution": "bundler",
|
|
23
|
+
"paths": {
|
|
24
|
+
"@/*": ["./src/*"],
|
|
25
|
+
"@/.source/*": ["./.source/*"]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"include": ["src", ".source", "source.config.ts"],
|
|
29
|
+
"exclude": ["node_modules", "dist"]
|
|
30
|
+
}
|