Files
rtu_v5/.planning/codebase/CONVENTIONS.md
2026-03-12 00:56:57 +08:00

240 lines
5.5 KiB
Markdown

# Coding Conventions
**Analysis Date:** 2026-03-12
## Language
**Primary:** JavaScript (Node.js)
- All source files use CommonJS (`.cjs` extension)
- ESM imports used in test files with `.test.cjs` extension
## File Naming
**Pattern:** kebab-case
- Commands: `allow-read-config.cjs`, `get-profile.cjs`, `set-profile.cjs`
- Libraries: `oc-core.cjs`, `oc-config.cjs`, `oc-models.cjs`
- Tests: `get-profile.test.cjs`, `allow-read-config.test.cjs`
**Directories:**
- Commands: `bin/gsd-oc-commands/`
- Libraries: `bin/gsd-oc-lib/` or `bin/lib/`
- Tests: `bin/test/`
## Code Style
### Formatting
**No explicit formatter configured.** Code uses:
- 2-space indentation
- Consistent brace placement
- Max line length ~100 characters
**Example from `bin/gsd-oc-commands/get-profile.cjs`:**
```javascript
function getProfile(cwd, args) {
const verbose = args.includes('--verbose');
const raw = args.includes('--raw');
const log = verbose ? (...args) => console.error('[get-profile]', ...args) : () => {};
// ...
}
```
### Linting
**No ESLint or Prettier configuration detected.**
## Import Organization
**Order in source files:**
1. Node.js built-ins (`fs`, `path`, `os`)
2. Local modules relative paths
**Example from `bin/gsd-oc-commands/allow-read-config.cjs`:**
```javascript
const fs = require('fs');
const path = require('path');
const os = require('os');
const { output, error, createBackup } = require('../gsd-oc-lib/oc-core.cjs');
```
## Function Design
### Naming
- Commands: lowercase with hyphens (e.g., `getProfile`, `allowReadConfig`)
- Helper functions: camelCase
- Error code constants: UPPER_SNAKE_CASE
### Documentation
**Every file includes a JSDoc-style header:**
```javascript
/**
* get-profile.cjs — Retrieve profile definitions from oc_config.json
*
* Command module that exports getProfile(cwd, args) function with two operation modes:
* 1. No parameters: Returns current profile definition
* 2. Profile name parameter: Returns specified profile definition
*
* Output format: JSON envelope {success: true, data: {...}}
* Flags: --raw (output raw JSON without envelope), --verbose (output diagnostics to stderr)
*
* Usage: node get-profile.cjs [profile-name] [--raw] [--verbose]
*/
```
**Function JSDoc:**
```javascript
/**
* Main command function
*
* @param {string} cwd - Current working directory
* @param {string[]} args - Command line arguments
*/
function getProfile(cwd, args) {
```
## Error Handling
### Error Codes
**Pattern:** Constant object with error codes, used with custom error function
From `bin/gsd-oc-lib/oc-profile-config.cjs`:
```javascript
const ERROR_CODES = {
CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
INVALID_JSON: 'INVALID_JSON',
PROFILE_NOT_FOUND: 'PROFILE_NOT_FOUND',
INVALID_MODELS: 'INVALID_MODELS',
INCOMPLETE_PROFILE: 'INCOMPLETE_PROFILE',
WRITE_FAILED: 'WRITE_FAILED',
APPLY_FAILED: 'APPLY_FAILED',
ROLLBACK_FAILED: 'ROLLBACK_FAILED'
};
```
### Output Pattern
**Success output:** JSON envelope with `success: true` and `data`
```javascript
output({ success: true, data: result });
```
**Error output:** Uses centralized `error()` function from `oc-core.cjs`
```javascript
error('current_oc_profile not set in oc_config.json', 'MISSING_CURRENT_PROFILE');
```
From `bin/gsd-oc-lib/oc-core.cjs`:
```javascript
function error(message, code = 'UNKNOWN_ERROR') {
const errorEnvelope = {
success: false,
error: {
code,
message
}
};
console.error(JSON.stringify(errorEnvelope, null, 2));
process.exit(1);
}
```
## Return Patterns
### Result Objects
**Pattern:** Return object with `success: boolean` and either `data` or `error`
From `bin/gsd-oc-lib/oc-profile-config.cjs`:
```javascript
function loadOcProfileConfig(cwd) {
try {
const configPath = path.join(cwd, '.planning', 'oc_config.json');
if (!fs.existsSync(configPath)) {
return {
success: false,
error: {
code: ERROR_CODES.CONFIG_NOT_FOUND,
message: `.planning/oc_config.json not found at ${configPath}`
}
};
}
return { success: true, config, configPath };
} catch (err) {
// ...
}
}
```
## Module Design
### Exports
**Pattern:** Single function export via `module.exports`
```javascript
module.exports = getProfile;
```
### Command Module Structure
1. JSDoc header with description
2. Require statements
3. Error code constants
4. Helper functions
5. Main command function
6. `module.exports`
## CLI Patterns
### Flag Handling
**Pattern:** Simple array filtering
```javascript
const verbose = args.includes('--verbose');
const raw = args.includes('--raw');
const profileArgs = args.filter(arg => !arg.startsWith('--'));
```
### Output Functions
From `bin/gsd-oc-lib/oc-core.cjs`:
```javascript
function output(result, raw = false, rawValue = null) {
let outputStr;
if (raw && rawValue !== null) {
outputStr = rawValue;
} else {
outputStr = JSON.stringify(result, null, 2);
}
// Large payload handling (>50KB)
if (outputStr.length > 50 * 1024) {
const tempFile = path.join(require('os').tmpdir(), `gsd-oc-${Date.now()}.json`);
fs.writeFileSync(tempFile, outputStr, 'utf8');
console.log(`@file:${tempFile}`);
} else {
console.log(outputStr);
}
}
```
## Logging
### Verbose Logging Pattern
**Conditional logging based on flag:**
```javascript
const log = verbose ? (...args) => console.error('[get-profile]', ...args) : () => {};
log('Loading oc_config.json');
log(`Config loaded from ${configPath}`);
```
## Testing Conventions
Tests co-located in `bin/test/` directory with `.test.cjs` suffix.
---
*Convention analysis: 2026-03-12*