Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
# run: pnpm exec tsc --noEmit

- name: Build
run: pnpm run build
run: pnpm run build:site
env:
NODE_ENV: production

Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ next-env.d.ts

# fumadocs
.source
.next
.next

# objectdocs
content/.objectdocs
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,21 @@ Add the following scripts to your `package.json`:
}
```

### 3. Add content
### 3. Initialize ObjectDocs

Run the init command to set up the site engine:

```bash
pnpm objectdocs init
```

This will:
- Copy the site engine to `content/.objectdocs`
- Install necessary dependencies
- Automatically add `content/.objectdocs` to `.gitignore`
- Prepare your project for development

### 4. Add content

Create the basic directory structure:

Expand Down Expand Up @@ -109,7 +123,7 @@ Create `content/docs/meta.json`:
}
```

### 4. Start the server
### 5. Start the server

```bash
pnpm dev
Expand All @@ -124,6 +138,7 @@ ObjectDocs enforces a clear directory structure to ensure maintainability at sca
```text
.
├── content/ # [Data Layer] Raw Content
│ ├── .objectdocs/ # Site engine (auto-generated by init)
│ ├── docs.site.json # Global settings (Nav, Logo, Branding)
│ └── docs/
│ ├── meta.json # Directory structure & sorting control
Expand Down
3 changes: 3 additions & 0 deletions examples/starter/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ pnpm-debug.log*
# TypeScript
*.tsbuildinfo
next-env.d.ts

# ObjectDocs
content/.objectdocs
15 changes: 14 additions & 1 deletion examples/starter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This starter template serves multiple purposes:
```
examples/starter/
├── content/
│ ├── .objectdocs/ # Site engine (created by init command)
│ ├── docs.site.json # Global site configuration
│ └── docs/
│ ├── meta.json # Sidebar navigation structure
Expand Down Expand Up @@ -55,7 +56,18 @@ cd examples/starter
pnpm install
```

This will install `@objectdocs/cli` from the workspace, which in turn will use `@objectdocs/site` as a dependency.
This will install `@objectdocs/cli` from the workspace.

3. Initialize ObjectDocs:

```bash
pnpm objectdocs init
```

This command will:
- Copy the `@objectdocs/site` engine to `content/.objectdocs`
- Install necessary dependencies
- Prepare your project for development

### Development

Expand Down Expand Up @@ -139,6 +151,7 @@ For more details on Vercel deployment, see [VERCEL.md](./VERCEL.md).
Use this checklist to validate the starter works correctly:

- [ ] `pnpm install` completes without errors
- [ ] `pnpm objectdocs init` initializes the site successfully
- [ ] `pnpm dev` starts the development server
- [ ] All pages load correctly in the browser
- [ ] Navigation works (sidebar, header links)
Expand Down
15 changes: 15 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ pnpm install

## Usage

### Initialize Site

Before using the development or build commands, you need to initialize the site:

```bash
# Initialize ObjectDocs site in content/.objectdocs
pnpm objectdocs init
```

This command:
- Copies the `@objectdocs/site` package to `content/.objectdocs`
- Installs necessary dependencies
- Automatically adds `content/.objectdocs` to `.gitignore`
- Prepares your project for local development

### Site Management

The CLI can also be used to run the documentation site locally with a VitePress-like experience.
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/bin/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@

import { cac } from 'cac';
import 'dotenv/config';
import { registerInitCommand } from '../src/commands/init.mjs';
import { registerTranslateCommand } from '../src/commands/translate.mjs';
import { registerDevCommand } from '../src/commands/dev.mjs';
import { registerBuildCommand } from '../src/commands/build.mjs';
import { registerStartCommand } from '../src/commands/start.mjs';

const cli = cac('objectdocs');

registerInitCommand(cli);
registerTranslateCommand(cli);
registerDevCommand(cli);
registerBuildCommand(cli);
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/src/commands/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ export function registerBuildCommand(cli) {
// 1. Resolve user's docs directory
const docsDir = dir ? path.resolve(process.cwd(), dir) : path.resolve(process.cwd(), 'content/docs');

// 2. Resolve the Next.js App directory
let nextAppDir;
try {
nextAppDir = path.dirname(require.resolve('@objectdocs/site/package.json'));
} catch (e) {
// Fallback for local development
nextAppDir = path.resolve(__dirname, '../../../site');
// 2. Resolve the Next.js App directory - use local .objectdocs first
let nextAppDir = path.resolve(process.cwd(), 'content/.objectdocs');

if (!fs.existsSync(nextAppDir)) {
console.log('⚠️ ObjectDocs site not found at content/.objectdocs');
console.log(' Run "objectdocs init" first to initialize the site.\n');
process.exit(1);
}

// Copy user config and assets to nextAppDir
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/src/commands/dev.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ export function registerDevCommand(cli) {
// 1. Resolve user's docs directory (Absolute path)
const docsDir = dir ? path.resolve(process.cwd(), dir) : path.resolve(process.cwd(), 'content/docs');

// 2. Resolve the Next.js App directory
let nextAppDir;
try {
nextAppDir = path.dirname(require.resolve('@objectdocs/site/package.json'));
} catch (e) {
// Fallback for local development
nextAppDir = path.resolve(__dirname, '../../../site');
// 2. Resolve the Next.js App directory - use local .objectdocs first
let nextAppDir = path.resolve(process.cwd(), 'content/.objectdocs');

if (!fs.existsSync(nextAppDir)) {
console.log('⚠️ ObjectDocs site not found at content/.objectdocs');
console.log(' Run "objectdocs init" first to initialize the site.\n');
process.exit(1);
}

console.log(`Starting docs server...`);
Expand Down
112 changes: 112 additions & 0 deletions packages/cli/src/commands/init.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* ObjectDocs
* Copyright (c) 2026-present ObjectStack Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { spawn } from 'child_process';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { createRequire } from 'module';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const require = createRequire(import.meta.url);

export function registerInitCommand(cli) {
cli
.command('init', 'Initialize ObjectDocs site in content/.objectdocs')
.action(async (options) => {
console.log('Initializing ObjectDocs...\n');

const targetDir = path.resolve(process.cwd(), 'content/.objectdocs');

// Check if already initialized
if (fs.existsSync(targetDir)) {
console.log(`⚠️ ObjectDocs already initialized at ${targetDir}`);
console.log(' Delete the directory if you want to reinitialize.\n');
return;
}

// Resolve the site package directory
let siteDir;
try {
siteDir = path.dirname(require.resolve('@objectdocs/site/package.json'));
} catch (e) {
// Fallback for local development
siteDir = path.resolve(__dirname, '../../../site');
}

console.log(`📦 Copying site from: ${siteDir}`);
console.log(`📁 Target directory: ${targetDir}\n`);

// Create target directory
fs.mkdirSync(targetDir, { recursive: true });

// Copy site files to target directory
fs.cpSync(siteDir, targetDir, {
recursive: true,
filter: (source) => {
const basename = path.basename(source);
// Skip node_modules, .next, and other build artifacts
if (basename === 'node_modules' ||
basename === '.next' ||
basename === 'out' ||
basename === '.turbo' ||
basename === 'dist') {
return false;
}
return true;
}
});

console.log('✅ ObjectDocs site copied successfully!\n');

// Add to .gitignore
const gitignorePath = path.resolve(process.cwd(), '.gitignore');
const gitignoreEntry = 'content/.objectdocs';

try {
let gitignoreContent = '';
if (fs.existsSync(gitignorePath)) {
gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');
}

// Check if the entry already exists (as a complete line)
const lines = gitignoreContent.split('\n').map(line => line.trim());
if (!lines.includes(gitignoreEntry)) {
// Add the entry with a comment
const separator = gitignoreContent.trim() ? '\n\n' : '';
const newContent = `${gitignoreContent.trim()}${separator}# ObjectDocs\n${gitignoreEntry}\n`;
fs.writeFileSync(gitignorePath, newContent);
console.log('📝 Added content/.objectdocs to .gitignore\n');
}
} catch (e) {
console.warn('⚠️ Could not update .gitignore:', e.message);
}

// Install dependencies in the target directory
console.log('📦 Installing dependencies...\n');

const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const installProcess = spawn(npmCmd, ['install', '--legacy-peer-deps'], {
cwd: targetDir,
stdio: 'inherit'
});

installProcess.on('close', (code) => {
if (code === 0) {
console.log('\n✅ Dependencies installed successfully!');
console.log('\n🎉 ObjectDocs initialized! You can now run:');
console.log(' pnpm dev - Start development server');
console.log(' pnpm build - Build for production\n');
} else {
console.error('\n❌ Failed to install dependencies');
process.exit(code);
}
});
});
}
13 changes: 7 additions & 6 deletions packages/cli/src/commands/start.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ const require = createRequire(import.meta.url);
export function registerStartCommand(cli) {
cli.command('start [dir]', 'Start the production server')
.action((dir) => {
// 1. Resolve Next.js App directory
let nextAppDir;
try {
nextAppDir = path.dirname(require.resolve('@objectdocs/site/package.json'));
} catch (e) {
nextAppDir = path.resolve(__dirname, '../../../site');
// 1. Resolve Next.js App directory - use local .objectdocs first
let nextAppDir = path.resolve(process.cwd(), 'content/.objectdocs');

if (!fs.existsSync(nextAppDir)) {
console.log('⚠️ ObjectDocs site not found at content/.objectdocs');
console.log(' Run "objectdocs init" first to initialize the site.\n');
process.exit(1);
}

// 2. Check config
Expand Down
Loading