From 9e619466a185eacb10354130b528d4c6c7f44867 Mon Sep 17 00:00:00 2001 From: shafeeqd959 Date: Wed, 25 Mar 2026 13:06:25 +0530 Subject: [PATCH] chore: update Cursor rules and commands for modularized CLI Update all Cursor configuration files based on this repository's actual structure and patterns. This repository is a modularized monorepo with 6 packages (contentstack, contentstack-auth, contentstack-config, contentstack-command, contentstack-utilities, contentstack-dev-dependencies). Changes: - Updated .cursor/rules/README.md with accurate package overview and rule loading behavior specific to this monorepo structure - Rewrote dev-workflow.md to reflect actual monorepo patterns, pnpm workspace setup, and 6-package structure - Updated typescript.mdc with actual tsconfig settings (strict: false, target: es2017, commonjs module) - Updated testing.mdc for Mocha/Chai patterns (removed Sinon references not heavily used in this repo) - Updated oclif-commands.mdc with actual command structure and patterns from this CLI - Deleted contentstack-cli.mdc (not applicable - no import/export modules) - Updated code-review.md with checklist for modularized CLI packages - Updated execute-tests.md with correct package names and monorepo patterns All rules now match the actual repository structure and development patterns, enabling more effective AI assistance in Cursor. Made-with: Cursor --- .cursor/commands/code-review.md | 154 +++++++++++++ .cursor/commands/execute-tests.md | 246 +++++++++++++++++++++ .cursor/rules/README.md | 80 +++++++ .cursor/rules/dev-workflow.md | 211 ++++++++++++++++++ .cursor/rules/oclif-commands.mdc | 352 ++++++++++++++++++++++++++++++ .cursor/rules/testing.mdc | 323 +++++++++++++++++++++++++++ .cursor/rules/typescript.mdc | 246 +++++++++++++++++++++ 7 files changed, 1612 insertions(+) create mode 100644 .cursor/commands/code-review.md create mode 100644 .cursor/commands/execute-tests.md create mode 100644 .cursor/rules/README.md create mode 100644 .cursor/rules/dev-workflow.md create mode 100644 .cursor/rules/oclif-commands.mdc create mode 100644 .cursor/rules/testing.mdc create mode 100644 .cursor/rules/typescript.mdc diff --git a/.cursor/commands/code-review.md b/.cursor/commands/code-review.md new file mode 100644 index 0000000000..14dd499df1 --- /dev/null +++ b/.cursor/commands/code-review.md @@ -0,0 +1,154 @@ +--- +name: code-review +description: Automated PR review using comprehensive checklist tailored for modularized Contentstack CLI +--- + +# Code Review Command + +## Usage Patterns + +### Scope-Based Reviews +- `/code-review` - Review all current changes with full checklist +- `/code-review --scope typescript` - Focus on TypeScript configuration and patterns +- `/code-review --scope testing` - Focus on Mocha/Chai test patterns +- `/code-review --scope oclif` - Focus on command structure and OCLIF patterns +- `/code-review --scope packages` - Focus on package structure and organization + +### Severity Filtering +- `/code-review --severity critical` - Show only critical issues (security, breaking changes) +- `/code-review --severity high` - Show high and critical issues +- `/code-review --severity all` - Show all issues including suggestions + +### Package-Aware Reviews +- `/code-review --package contentstack-config` - Review changes in specific package +- `/code-review --package-type plugin` - Review plugin packages only (auth, config) +- `/code-review --package-type library` - Review library packages (command, utilities, dev-dependencies) + +### File Type Focus +- `/code-review --files commands` - Review command files only +- `/code-review --files tests` - Review test files only +- `/code-review --files utils` - Review utility files + +## Comprehensive Review Checklist + +### Monorepo Structure Compliance +- **Package organization**: Proper placement in `packages/` structure +- **pnpm workspace**: Correct `package.json` workspace configuration +- **Build artifacts**: No `lib/` directories committed to version control +- **Dependencies**: Proper use of shared utilities (`@contentstack/cli-command`, `@contentstack/cli-utilities`) +- **Scripts**: Consistent build, test, and lint scripts across packages + +### Package-Specific Structure +- **Plugin packages** (auth, config): Have `oclif.commands` configuration +- **Library packages** (command, utilities, dev-dependencies): Proper exports in package.json +- **Main package** (contentstack): Aggregates plugins correctly +- **Dependency versions**: Using beta versions appropriately (~version ranges) + +### TypeScript Standards +- **Configuration compliance**: Follows package TypeScript config (`strict: false`, `target: es2017`) +- **Naming conventions**: kebab-case files, PascalCase classes, camelCase functions +- **Import patterns**: ES modules with proper default/named exports +- **Type safety**: No unnecessary `any` types in production code + +### OCLIF Command Patterns +- **Base class usage**: Extends `@contentstack/cli-command` Command +- **Command structure**: Proper `static description`, `static examples`, `static flags` +- **Topic organization**: Uses `cm` topic structure (`cm:config:set`, `cm:auth:login`) +- **Error handling**: Uses `handleAndLogError` from utilities +- **Flag validation**: Early validation and user-friendly error messages +- **Service delegation**: Commands orchestrate, services implement business logic + +### Testing Excellence (Mocha/Chai Stack) +- **Framework compliance**: Uses Mocha + Chai (not Jest) +- **File patterns**: Follows `*.test.ts` naming convention +- **Directory structure**: Proper placement in `test/unit/` +- **Test organization**: Arrange-Act-Assert pattern consistently used +- **Isolation**: Proper setup/teardown with beforeEach/afterEach +- **No real API calls**: All external dependencies properly mocked + +### Error Handling Standards +- **Consistent patterns**: Use `handleAndLogError` from utilities +- **User-friendly messages**: Clear error descriptions for end users +- **Logging**: Proper use of `log.debug` for diagnostic information +- **Status messages**: Use `cliux` for user feedback (success, error, info) + +### Build and Compilation +- **TypeScript compilation**: Clean compilation with no errors +- **OCLIF manifest**: Generated for command discovery +- **README generation**: Commands documented in package README +- **Source maps**: Properly configured for debugging +- **No build artifacts in commit**: `.gitignore` excludes `lib/` directories + +### Testing Coverage +- **Test structure**: Tests in `test/unit/` with descriptive names +- **Command testing**: Uses @oclif/test for command validation +- **Error scenarios**: Tests for both success and failure paths +- **Mocking**: All dependencies properly mocked + +### Package.json Compliance +- **Correct metadata**: name, description, version, author +- **Script definitions**: build, compile, test, lint scripts present +- **Dependencies**: Correct versions of shared packages +- **Main/types**: Properly configured for library packages +- **OCLIF config**: Present for plugin packages + +### Security and Best Practices +- **No secrets**: No API keys or tokens in code or tests +- **Input validation**: Proper validation of user inputs and flags +- **Process management**: Appropriate use of error codes +- **File operations**: Safe handling of file system operations + +### Code Quality +- **Naming consistency**: Follow established conventions +- **Comments**: Only for non-obvious logic (no "narration" comments) +- **Error messages**: Clear, actionable messages for users +- **Module organization**: Proper separation of concerns + +## Review Execution + +### Automated Checks +1. **Lint compliance**: ESLint checks for code style +2. **TypeScript compiler**: Successful compilation to `lib/` directories +3. **Test execution**: All tests pass successfully +4. **Build verification**: Build scripts complete without errors + +### Manual Review Focus Areas +1. **Command usability**: Clear help text and realistic examples +2. **Error handling**: Appropriate error messages and recovery options +3. **Test quality**: Comprehensive test coverage for critical paths +4. **Monorepo consistency**: Consistent patterns across all packages +5. **Flag design**: Intuitive flag names and combinations + +### Common Issues to Flag +- **Inconsistent TypeScript settings**: Mixed strict mode without reason +- **Real API calls in tests**: Unmocked external dependencies +- **Missing error handling**: Commands that fail silently +- **Poor test organization**: Tests without clear Arrange-Act-Assert +- **Build artifacts committed**: `lib/` directories in version control +- **Unclear error messages**: Non-actionable error descriptions +- **Inconsistent flag naming**: Similar flags with different names +- **Missing command examples**: Examples not showing actual usage + +## Repository-Specific Checklist + +### For Modularized CLI +- [ ] Command properly extends `@contentstack/cli-command` Command +- [ ] Flags defined with proper types from `@contentstack/cli-utilities` +- [ ] Error handling uses `handleAndLogError` utility +- [ ] User feedback uses `cliux` utilities +- [ ] Tests use Mocha + Chai pattern with mocked dependencies +- [ ] Package.json has correct scripts (build, compile, test, lint) +- [ ] TypeScript compiles with no errors +- [ ] Tests pass: `pnpm test` +- [ ] No `.only` or `.skip` in test files +- [ ] Build succeeds: `pnpm run build` +- [ ] OCLIF manifest generated successfully + +### Before Merge +- [ ] All review items addressed +- [ ] No build artifacts in commit +- [ ] Tests added for new functionality +- [ ] Documentation updated if needed +- [ ] No console.log() statements (use log.debug instead) +- [ ] Error messages are user-friendly +- [ ] No secrets or credentials in code diff --git a/.cursor/commands/execute-tests.md b/.cursor/commands/execute-tests.md new file mode 100644 index 0000000000..fb473ecf26 --- /dev/null +++ b/.cursor/commands/execute-tests.md @@ -0,0 +1,246 @@ +--- +name: execute-tests +description: Run tests by scope, file, or module with intelligent filtering for this pnpm monorepo +--- + +# Execute Tests Command + +## Usage Patterns + +### Monorepo-Wide Testing +- `/execute-tests` - Run all tests across all packages +- `/execute-tests --coverage` - Run all tests with coverage reporting +- `/execute-tests --parallel` - Run package tests in parallel using pnpm + +### Package-Specific Testing +- `/execute-tests contentstack-config` - Run tests for config package +- `/execute-tests contentstack-auth` - Run tests for auth package +- `/execute-tests contentstack-command` - Run tests for command package +- `/execute-tests contentstack-utilities` - Run tests for utilities package +- `/execute-tests packages/contentstack-config/` - Run tests using path + +### Scope-Based Testing +- `/execute-tests unit` - Run unit tests only (`test/unit/**/*.test.ts`) +- `/execute-tests commands` - Run command tests (`test/unit/commands/**/*.test.ts`) +- `/execute-tests services` - Run service layer tests + +### File Pattern Testing +- `/execute-tests *.test.ts` - Run all TypeScript tests +- `/execute-tests test/unit/commands/` - Run tests for specific directory + +### Watch and Development +- `/execute-tests --watch` - Run tests in watch mode with file monitoring +- `/execute-tests --debug` - Run tests with debug output enabled +- `/execute-tests --bail` - Stop on first test failure + +## Intelligent Filtering + +### Repository-Aware Detection +- **Test patterns**: All use `*.test.ts` naming convention +- **Directory structures**: Standard `test/unit/` layout +- **Test locations**: `packages/*/test/unit/**/*.test.ts` +- **Build exclusion**: Ignores `lib/` directories (compiled artifacts) + +### Package Structure +The monorepo contains 6 packages: +- `contentstack` - Main CLI package +- `contentstack-auth` - Authentication plugin +- `contentstack-config` - Configuration plugin +- `contentstack-command` - Base Command class (library) +- `contentstack-utilities` - Utilities library +- `contentstack-dev-dependencies` - Dev dependencies + +### Monorepo Integration +- **pnpm workspace support**: Uses `pnpm -r --filter` for package targeting +- **Dependency awareness**: Understands package interdependencies +- **Parallel execution**: Leverages pnpm's parallel capabilities +- **Selective testing**: Can target specific packages or file patterns + +### Framework Detection +- **Mocha configuration**: Respects `.mocharc.json` files per package +- **TypeScript compilation**: Handles test TypeScript setup +- **Test setup**: Detects test helper initialization files +- **Test timeout**: 30 seconds standard (configurable per package) + +## Execution Examples + +### Common Workflows +```bash +# Run all tests with coverage +/execute-tests --coverage + +# Test specific package during development +/execute-tests contentstack-config --watch + +# Run only command tests across all packages +/execute-tests commands + +# Run unit tests with detailed output +/execute-tests --debug + +# Test until first failure (quick feedback) +/execute-tests --bail +``` + +### Package-Specific Commands Generated +```bash +# For contentstack-config package +cd packages/contentstack-config && pnpm test + +# For all packages with parallel execution +pnpm -r --filter './packages/*' run test + +# For specific test file +cd packages/contentstack-config && npx mocha "test/unit/commands/region.test.ts" + +# With coverage +pnpm -r --filter './packages/*' run test:coverage +``` + +## Configuration Awareness + +### Mocha Integration +- Respects individual package `.mocharc.json` configurations +- Handles TypeScript compilation via ts-node/register +- Supports test helpers and initialization files +- Manages timeout settings per package (default 30 seconds) + +### Test Configuration +```json +// .mocharc.json +{ + "require": [ + "test/helpers/init.js", + "ts-node/register", + "source-map-support/register" + ], + "recursive": true, + "timeout": 30000, + "spec": "test/**/*.test.ts" +} +``` + +### pnpm Workspace Features +- Leverages workspace dependency resolution +- Supports filtered execution by package patterns +- Enables parallel test execution across packages +- Respects package-specific scripts and configurations + +## Test Structure + +### Standard Test Organization +``` +packages/*/ +├── test/ +│ └── unit/ +│ ├── commands/ # Command-specific tests +│ ├── services/ # Service/business logic tests +│ └── utils/ # Utility function tests +└── src/ + ├── commands/ # CLI commands + ├── services/ # Business logic + └── utils/ # Utilities +``` + +### Test File Naming +- **Pattern**: `*.test.ts` across all packages +- **Location**: `test/unit/` directories +- **Organization**: Mirrors `src/` structure for easy navigation + +## Performance Optimization + +### Parallel Testing +```bash +# Run tests in parallel for faster feedback +pnpm -r --filter './packages/*' run test + +# Watch mode during development +/execute-tests --watch +``` + +### Selective Testing +- Run only affected packages' tests during development +- Use `--bail` to stop on first failure for quick iteration +- Target specific test files for focused debugging + +## Troubleshooting + +### Common Issues + +**Tests not found** +- Check that files follow `*.test.ts` pattern +- Verify files are in `test/unit/` directory +- Ensure `.mocharc.json` has correct spec pattern + +**TypeScript compilation errors** +- Verify `tsconfig.json` in package root +- Check that `ts-node/register` is in `.mocharc.json` requires +- Run `pnpm compile` to check TypeScript errors + +**Watch mode not detecting changes** +- Verify `--watch` flag is supported in your Mocha version +- Check that file paths are correct +- Ensure no excessive `.gitignore` patterns + +**Port conflicts** +- Tests should not use hard-coded ports +- Use dynamic port allocation or test isolation +- Check for process cleanup in `afterEach` hooks + +## Best Practices + +### Test Execution +- Run tests before committing: `pnpm test` +- Use `--bail` during development for quick feedback +- Run full suite before opening PR +- Check coverage for critical paths + +### Test Organization +- Keep tests close to source code structure +- Use descriptive test names +- Group related tests with `describe` blocks +- Clean up resources in `afterEach` + +### Debugging +- Use `--debug` flag for detailed output +- Add `log.debug()` statements in tests +- Run individual test files for isolation +- Use `--bail` to stop at first failure + +## Integration with CI/CD + +### GitHub Actions +- Runs `pnpm test` on pull requests +- Enforces test passage before merge +- May include coverage reporting +- Runs linting and build verification + +### Local Development +```bash +# Before committing +pnpm test +pnpm run lint +pnpm run build + +# Or use watch mode for faster iteration +pnpm test --watch +``` + +## Coverage Reporting + +### Coverage Commands +```bash +# Run tests with coverage +/execute-tests --coverage + +# Coverage output location +coverage/ +├── index.html # HTML report +├── coverage-summary.json # JSON summary +└── lcov.info # LCOV format +``` + +### Coverage Goals +- **Team aspiration**: 80% minimum coverage +- **Focus on**: Critical business logic and error paths +- **Not critical**: Utility functions and edge cases diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 0000000000..8da5ddffcf --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,80 @@ +# Cursor Rules + +Context-aware rules that load automatically based on the files you're editing, optimized for this modularized Contentstack CLI. + +## Rule Files + +| File | Scope | Always Applied | Purpose | +|------|-------|----------------|---------| +| `dev-workflow.md` | `**/*.ts`, `**/*.js`, `**/*.json` | Yes | Monorepo TDD workflow, pnpm workspace patterns (6 packages) | +| `typescript.mdc` | `**/*.ts`, `**/*.tsx` | No | TypeScript configurations and naming conventions | +| `testing.mdc` | `**/test/**/*.ts`, `**/test/**/*.js`, `**/__tests__/**/*.ts`, `**/*.spec.ts`, `**/*.test.ts` | Yes | Mocha, Chai test patterns and test structure | +| `oclif-commands.mdc` | `**/commands/**/*.ts` | No | OCLIF command patterns and CLI validation | + +## Commands + +| File | Trigger | Purpose | +|------|---------|---------| +| `execute-tests.md` | `/execute-tests` | Run tests by scope, package, or module with monorepo awareness | +| `code-review.md` | `/code-review` | Automated PR review with CLI-specific checklist | + +## Loading Behaviour + +### File Type Mapping +- **TypeScript files** → `typescript.mdc` + `dev-workflow.md` +- **Command files** (`packages/*/src/commands/**/*.ts`) → `oclif-commands.mdc` + `typescript.mdc` + `dev-workflow.md` +- **Test files** (`packages/*/test/**/*.{ts,js}`) → `testing.mdc` + `dev-workflow.md` +- **Utility files** (`packages/*/src/utils/**/*.ts`) → `typescript.mdc` + `dev-workflow.md` + +### Package-Specific Loading +- **Plugin packages** (with `oclif.commands`) → Full command and utility rules +- **Library packages** → TypeScript and utility rules only + +## Repository-Specific Features + +### Monorepo Structure +- **6 packages** under `packages/`: + - `contentstack` - Main CLI entry point (bin/run.js) + - `contentstack-auth` - Authentication plugin + - `contentstack-config` - Configuration plugin + - `contentstack-command` - Base Command class for plugins + - `contentstack-utilities` - Shared utilities and helpers + - `contentstack-dev-dependencies` - Development dependencies + +### Build Configuration +- **pnpm workspaces** configuration +- **Shared dependencies**: `@contentstack/cli-command`, `@contentstack/cli-utilities` +- **Build process**: TypeScript compilation → `lib/` directories +- **OCLIF manifest** generation for command discovery + +### Actual Patterns Detected +- **Testing**: Mocha + Chai (not Jest or Sinon-heavy) +- **TypeScript**: Mixed strict mode adoption +- **Commands**: Extend `@oclif/core` Command class +- **Build artifacts**: `lib/` directories (excluded from rules) + +## Performance Benefits + +- **Lightweight loading** - Only relevant rules activate based on file patterns +- **Precise glob patterns** - Avoid loading rules for build artifacts +- **Context-aware** - Rules load based on actual file structure + +## Design Principles + +### Validated Against Codebase +- Rules reflect **actual patterns** found in repository +- Glob patterns match **real file structure** +- Examples use **actual dependencies** and APIs + +### Lightweight and Focused +- Each rule has **single responsibility** +- Package-specific variations acknowledged +- `alwaysApply: true` only for truly universal patterns + +## Quick Reference + +For detailed patterns: +- **Testing**: See `testing.mdc` for Mocha/Chai test structure +- **Commands**: See `oclif-commands.mdc` for command development +- **Development**: See `dev-workflow.md` for TDD and monorepo workflow +- **TypeScript**: See `typescript.mdc` for type safety patterns diff --git a/.cursor/rules/dev-workflow.md b/.cursor/rules/dev-workflow.md new file mode 100644 index 0000000000..517867b0ef --- /dev/null +++ b/.cursor/rules/dev-workflow.md @@ -0,0 +1,211 @@ +--- +description: "Core development workflow and TDD patterns - always applied" +globs: ["**/*.ts", "**/*.js", "**/*.json"] +alwaysApply: true +--- + +# Development Workflow + +## Monorepo Structure + +### Package Organization +This modularized CLI has 6 packages under `packages/`: + +1. **contentstack** - Main CLI package + - Entry point: `bin/run.js` + - Aggregates all plugins + +2. **contentstack-auth** - Authentication plugin + - Commands: `cm:auth:*` + - Handles login/logout flows + +3. **contentstack-config** - Configuration plugin + - Commands: `cm:config:*`, `cm:region:*`, etc. + - Manages CLI settings and preferences + +4. **contentstack-command** - Base Command class (library) + - Shared Command base for all plugins + - Utilities and helpers for command development + +5. **contentstack-utilities** - Utilities library + - Shared helpers and utilities + - Used by all packages + +6. **contentstack-dev-dependencies** - Dev dependencies + - Centralized development dependencies + +### pnpm Workspace Configuration +```json +{ + "workspaces": ["packages/*"] +} +``` + +### Development Commands +```bash +# Install dependencies for all packages +pnpm install + +# Run command across all packages +pnpm -r --filter './packages/*' + +# Work on specific package +cd packages/contentstack-config +pnpm test +``` + +## TDD Workflow - MANDATORY + +1. **RED** → Write ONE failing test in `test/unit/**/*.test.ts` +2. **GREEN** → Write minimal code in `src/` to pass +3. **REFACTOR** → Improve code quality while keeping tests green + +### Test-First Examples +```typescript +// ✅ GOOD - Write test first +describe('ConfigService', () => { + it('should load configuration', async () => { + // Arrange - Set up mocks + const mockConfig = { region: 'us', alias: 'default' }; + + // Act - Call the method + const result = await configService.load(); + + // Assert - Verify behavior + expect(result).to.deep.equal(mockConfig); + }); +}); +``` + +## Critical Rules + +### Testing Standards +- **NO implementation before tests** - Test-driven development only +- **Mock all external dependencies** - No real API calls in tests +- **Use Mocha + Chai** - Standard testing stack +- **Coverage aspiration**: 80% minimum + +### Code Quality +- **TypeScript configuration**: Varies by package +- **NO test.skip or .only in commits** - Clean test suites only +- **Proper error handling** - Clear error messages + +### Build Process +```bash +# Standard build process for each package +pnpm run build # tsc compilation + oclif manifest +pnpm run test # Run test suite +pnpm run lint # ESLint checks +``` + +## Package-Specific Patterns + +### Plugin Packages (auth, config) +- Have `oclif.commands` in `package.json` +- Commands in `src/commands/cm/**/*.ts` +- Built commands in `lib/commands/` +- Extend `@oclif/core` Command class +- Script: `build`: compiles TypeScript, generates OCLIF manifest and README + +### Library Packages (command, utilities, dev-dependencies) +- No OCLIF commands configuration +- Pure TypeScript/JavaScript libraries +- Consumed by other packages +- `main` points to `lib/index.js` + +### Main CLI Package (contentstack) +- Entry point through `bin/run.js` +- Aggregates plugin commands +- Package dependencies reference plugin packages + +## Script Conventions + +### Build Scripts +```json +{ + "build": "pnpm compile && oclif manifest && oclif readme", + "compile": "tsc -b tsconfig.json", + "prepack": "pnpm compile && oclif manifest && oclif readme", + "test": "mocha \"test/unit/**/*.test.ts\"", + "lint": "eslint src/**/*.ts" +} +``` + +### Key Build Steps +1. **compile** - TypeScript compilation to `lib/` +2. **oclif manifest** - Generate command manifest for discovery +3. **oclif readme** - Generate command documentation + +## Quick Reference + +For detailed patterns, see: +- `@testing` - Mocha, Chai test patterns +- `@oclif-commands` - Command structure and validation +- `@dev-workflow` (this document) - Monorepo workflow and TDD + +## Development Checklist + +### Before Starting Work +- [ ] Identify target package in `packages/` +- [ ] Check existing tests in `test/unit/` +- [ ] Understand command structure if working on commands +- [ ] Set up proper TypeScript configuration + +### During Development +- [ ] Write failing test first +- [ ] Implement minimal code to pass +- [ ] Mock external dependencies +- [ ] Follow naming conventions (kebab-case files, PascalCase classes) + +### Before Committing +- [ ] All tests pass: `pnpm test` +- [ ] No `.only` or `.skip` in test files +- [ ] Build succeeds: `pnpm run build` +- [ ] TypeScript compilation clean +- [ ] Proper error handling implemented + +## Common Patterns + +### Service/Class Architecture +```typescript +// ✅ GOOD - Separate concerns +export default class ConfigCommand extends Command { + static description = 'Manage CLI configuration'; + + async run(): Promise { + try { + const service = new ConfigService(); + await service.execute(); + this.log('Configuration updated successfully'); + } catch (error) { + this.error('Configuration update failed'); + } + } +} +``` + +### Error Handling +```typescript +// ✅ GOOD - Clear error messages +try { + await this.performAction(); +} catch (error) { + if (error instanceof ValidationError) { + this.error(`Invalid input: ${error.message}`); + } else { + this.error('Operation failed'); + } +} +``` + +## CI/CD Integration + +### GitHub Actions +- Uses workflow files in `.github/workflows/` +- Runs linting, tests, and builds on pull requests +- Enforces code quality standards + +### Pre-commit Hooks +- Husky integration for pre-commit checks +- Prevents commits with linting errors +- Located in `.husky/` diff --git a/.cursor/rules/oclif-commands.mdc b/.cursor/rules/oclif-commands.mdc new file mode 100644 index 0000000000..832841c0b9 --- /dev/null +++ b/.cursor/rules/oclif-commands.mdc @@ -0,0 +1,352 @@ +--- +description: 'OCLIF command development patterns and CLI best practices' +globs: ['**/commands/**/*.ts'] +alwaysApply: false +--- + +# OCLIF Command Standards + +## Command Structure + +### Standard Command Pattern +```typescript +// ✅ GOOD - Standard command structure +import { Command } from '@contentstack/cli-command'; +import { cliux, flags, FlagInput, handleAndLogError } from '@contentstack/cli-utilities'; + +export default class ConfigSetCommand extends Command { + static description = 'Set CLI configuration values'; + + static flags: FlagInput = { + region: flags.string({ + char: 'r', + description: 'Set region (us/eu)', + }), + alias: flags.string({ + char: 'a', + description: 'Configuration alias', + }), + }; + + static examples = [ + 'csdx config:set --region eu', + 'csdx config:set --region us --alias default', + ]; + + async run(): Promise { + try { + const { flags: configFlags } = await this.parse(ConfigSetCommand); + // Command logic here + } catch (error) { + handleAndLogError(error, { module: 'config-set' }); + } + } +} +``` + +## Base Classes + +### Command Base Class +```typescript +// ✅ GOOD - Extend Command from @contentstack/cli-command +import { Command } from '@contentstack/cli-command'; + +export default class MyCommand extends Command { + async run(): Promise { + // Command implementation + } +} +``` + +### Custom Base Classes +```typescript +// ✅ GOOD - Create custom base classes for shared functionality +export abstract class BaseCommand extends Command { + protected contextDetails = { + command: this.id || 'unknown', + }; + + async init(): Promise { + await super.init(); + log.debug('Command initialized', this.contextDetails); + } +} +``` + +## OCLIF Configuration + +### Package.json Setup +```json +{ + "oclif": { + "commands": "./lib/commands", + "bin": "csdx", + "topicSeparator": ":" + } +} +``` + +### Command Topics +- All commands use `cm` topic: `cm:config:set`, `cm:auth:login` +- Built commands live in `lib/commands` (compiled from `src/commands`) +- Commands use nested directories: `src/commands/config/set.ts` → `cm:config:set` + +### Command Naming +- **Topic hierarchy**: `config/remove/proxy.ts` → `cm:config:remove:proxy` +- **Descriptive names**: Use verb-noun pattern (`set`, `remove`, `show`) +- **Grouping**: Related commands share parent topics + +## Flag Management + +### Flag Definition Patterns +```typescript +// ✅ GOOD - Define flags clearly +static flags: FlagInput = { + 'stack-api-key': flags.string({ + char: 'k', + description: 'Stack API key', + required: false, + }), + region: flags.string({ + char: 'r', + description: 'Set region', + options: ['us', 'eu'], + }), + verbose: flags.boolean({ + char: 'v', + description: 'Show verbose output', + default: false, + }), +}; +``` + +### Flag Parsing +```typescript +// ✅ GOOD - Parse and validate flags +async run(): Promise { + const { flags: parsedFlags } = await this.parse(MyCommand); + + // Validate flag combinations + if (!parsedFlags['stack-api-key'] && !parsedFlags.alias) { + this.error('Either --stack-api-key or --alias is required'); + } + + // Use parsed flags + const region = parsedFlags.region || 'us'; +} +``` + +## Error Handling + +### Standard Error Pattern +```typescript +// ✅ GOOD - Use handleAndLogError from utilities +try { + await this.executeCommand(); +} catch (error) { + handleAndLogError(error, { module: 'my-command' }); +} +``` + +### User-Friendly Messages +```typescript +// ✅ GOOD - Clear user feedback +import { cliux } from '@contentstack/cli-utilities'; + +// Success message +cliux.success('Configuration updated successfully', { color: 'green' }); + +// Error message +cliux.error('Invalid region specified', { color: 'red' }); + +// Info message +cliux.print('Setting region to eu', { color: 'blue' }); +``` + +## Validation Patterns + +### Early Validation +```typescript +// ✅ GOOD - Validate flags early +async run(): Promise { + const { flags } = await this.parse(MyCommand); + + // Validate required flags + if (!flags.region) { + this.error('--region is required'); + } + + // Validate flag values + if (!['us', 'eu'].includes(flags.region)) { + this.error('Region must be "us" or "eu"'); + } + + // Proceed with validated input +} +``` + +## Progress and Logging + +### User Feedback +```typescript +// ✅ GOOD - Provide user feedback +import { log, cliux } from '@contentstack/cli-utilities'; + +// Regular logging +this.log('Starting configuration update...'); + +// Debug logging +log.debug('Detailed operation information', { context: 'data' }); + +// Status messages +cliux.print('Processing...', { color: 'blue' }); +``` + +### Progress Indication +```typescript +// ✅ GOOD - Show progress for long operations +cliux.print('Processing items...', { color: 'blue' }); +let count = 0; +for (const item of items) { + await this.processItem(item); + count++; + cliux.print(`Processed ${count}/${items.length} items`, { color: 'blue' }); +} +``` + +## Command Delegation + +### Service Layer Separation +```typescript +// ✅ GOOD - Commands orchestrate, services implement +async run(): Promise { + try { + const { flags } = await this.parse(MyCommand); + const config = this.buildConfig(flags); + const service = new ConfigService(config); + + await service.execute(); + cliux.success('Operation completed successfully'); + } catch (error) { + this.handleError(error); + } +} +``` + +## Testing Commands + +### OCLIF Test Support +```typescript +// ✅ GOOD - Use @oclif/test for command testing +import { test } from '@oclif/test'; + +describe('cm:config:set', () => { + test + .stdout() + .command(['cm:config:set', '--help']) + .it('shows help', ctx => { + expect(ctx.stdout).to.contain('Set CLI configuration'); + }); + + test + .stdout() + .command(['cm:config:set', '--region', 'eu']) + .it('sets region to eu', ctx => { + expect(ctx.stdout).to.contain('success'); + }); +}); +``` + +## Log Integration + +### Debug Logging +```typescript +// ✅ GOOD - Use structured debug logging +import { log } from '@contentstack/cli-utilities'; + +log.debug('Command started', { + command: this.id, + flags: this.flags, + timestamp: new Date().toISOString(), +}); + +log.debug('Processing complete', { + itemsProcessed: count, + module: 'my-command', +}); +``` + +### Error Context +```typescript +// ✅ GOOD - Include context in error handling +try { + await operation(); +} catch (error) { + handleAndLogError(error, { + module: 'config-set', + command: 'cm:config:set', + flags: { region: 'eu' }, + }); +} +``` + +## Multi-Topic Commands + +### Nested Command Structure +```typescript +// File: src/commands/config/show.ts +export default class ShowConfigCommand extends Command { + static description = 'Show current configuration'; + static examples = ['csdx config:show']; + async run(): Promise { } +} + +// File: src/commands/config/set.ts +export default class SetConfigCommand extends Command { + static description = 'Set configuration values'; + static examples = ['csdx config:set --region eu']; + async run(): Promise { } +} + +// Generated commands: +// - cm:config:show +// - cm:config:set +``` + +## Best Practices + +### Command Organization +```typescript +// ✅ GOOD - Well-organized command +export default class MyCommand extends Command { + static description = 'Clear, concise description'; + + static flags: FlagInput = { + // Define all flags + }; + + static examples = [ + 'csdx my:command', + 'csdx my:command --flag value', + ]; + + async run(): Promise { + try { + const { flags } = await this.parse(MyCommand); + await this.execute(flags); + } catch (error) { + handleAndLogError(error, { module: 'my-command' }); + } + } + + private async execute(flags: Flags): Promise { + // Implementation + } +} +``` + +### Clear Help Text +- Write description as action-oriented statement +- Provide multiple examples for common use cases +- Document each flag with clear description +- Show output format or examples of results diff --git a/.cursor/rules/testing.mdc b/.cursor/rules/testing.mdc new file mode 100644 index 0000000000..daf6de1089 --- /dev/null +++ b/.cursor/rules/testing.mdc @@ -0,0 +1,323 @@ +--- +description: 'Testing patterns and TDD workflow' +globs: ['**/test/**/*.ts', '**/test/**/*.js', '**/__tests__/**/*.ts', '**/*.spec.ts', '**/*.test.ts'] +alwaysApply: true +--- + +# Testing Standards + +## Framework Stack + +### Primary Testing Tools +- **Mocha** - Test runner (used across all packages) +- **Chai** - Assertion library +- **@oclif/test** - Command testing support (for plugin packages) + +### Test Setup +- TypeScript compilation via ts-node/register +- Source map support for stack traces +- Global test timeout: 30 seconds (configurable per package) + +## Test File Patterns + +### Naming Conventions +- **Primary**: `*.test.ts` (standard pattern across all packages) +- **Location**: `test/unit/**/*.test.ts` (most packages) + +### Directory Structure +``` +packages/*/ +├── test/ +│ └── unit/ +│ ├── commands/ # Command-specific tests +│ ├── services/ # Service/business logic tests +│ └── utils/ # Utility function tests +└── src/ # Source code + ├── commands/ # CLI commands + ├── services/ # Business logic + └── utils/ # Utilities +``` + +## Mocha Configuration + +### Standard Setup (.mocharc.json) +```json +{ + "require": [ + "test/helpers/init.js", + "ts-node/register", + "source-map-support/register" + ], + "recursive": true, + "timeout": 30000, + "spec": "test/**/*.test.ts" +} +``` + +### TypeScript Compilation +```json +// package.json scripts +{ + "test": "mocha \"test/unit/**/*.test.ts\"", + "test:coverage": "nyc mocha \"test/unit/**/*.test.ts\"" +} +``` + +## Test Structure + +### Standard Test Pattern +```typescript +// ✅ GOOD - Comprehensive test structure +describe('ConfigService', () => { + let service: ConfigService; + + beforeEach(() => { + service = new ConfigService(); + }); + + describe('loadConfig()', () => { + it('should load configuration successfully', async () => { + // Arrange + const expectedConfig = { region: 'us' }; + + // Act + const result = await service.loadConfig(); + + // Assert + expect(result).to.deep.equal(expectedConfig); + }); + + it('should handle missing configuration', async () => { + // Arrange & Act & Assert + await expect(service.loadConfig()).to.be.rejectedWith('Config not found'); + }); + }); +}); +``` + +### Async/Await Pattern +```typescript +// ✅ GOOD - Use async/await in tests +it('should process data asynchronously', async () => { + const result = await service.processAsync(); + expect(result).to.exist; +}); + +// ✅ GOOD - Explicit Promise handling +it('should return a promise', () => { + return service.asyncMethod().then(result => { + expect(result).to.be.true; + }); +}); +``` + +## Mocking Patterns + +### Class Mocking +```typescript +// ✅ GOOD - Mock class dependencies +class MockConfigService { + async loadConfig() { + return { region: 'us' }; + } +} + +it('should use mocked service', async () => { + const mockService = new MockConfigService(); + const result = await mockService.loadConfig(); + expect(result.region).to.equal('us'); +}); +``` + +### Function Stubs +```typescript +// ✅ GOOD - Stub module functions if needed +beforeEach(() => { + // Stub file system operations + // Stub network calls +}); + +afterEach(() => { + // Restore original implementations +}); +``` + +## Command Testing + +### OCLIF Test Pattern +```typescript +// ✅ GOOD - Test commands with @oclif/test +import { test } from '@oclif/test'; + +describe('cm:config:region', () => { + test + .stdout() + .command(['cm:config:region', '--help']) + .it('shows help message', ctx => { + expect(ctx.stdout).to.contain('Display region'); + }); + + test + .stdout() + .command(['cm:config:region']) + .it('shows current region', ctx => { + expect(ctx.stdout).to.contain('us'); + }); +}); +``` + +### Command Flag Testing +```typescript +// ✅ GOOD - Test command flags and arguments +describe('cm:config:set', () => { + test + .command(['cm:config:set', '--help']) + .it('shows usage information'); + + test + .command(['cm:config:set', '--region', 'eu']) + .it('sets region to eu'); +}); +``` + +## Error Testing + +### Error Handling +```typescript +// ✅ GOOD - Test error scenarios +it('should throw ValidationError on invalid input', async () => { + const invalidInput = ''; + await expect(service.validate(invalidInput)) + .to.be.rejectedWith('Invalid input'); +}); + +it('should handle network errors gracefully', async () => { + // Mock network failure + const result = await service.fetchWithRetry(); + expect(result).to.be.null; +}); +``` + +### Error Types +```typescript +// ✅ GOOD - Test specific error types +it('should throw appropriate error', async () => { + try { + await service.failingOperation(); + } catch (error) { + expect(error).to.be.instanceof(ValidationError); + expect(error.code).to.equal('INVALID_CONFIG'); + } +}); +``` + +## Test Data Management + +### Mock Data Organization +```typescript +// ✅ GOOD - Organize test data +const mockData = { + validConfig: { + region: 'us', + timeout: 30000, + }, + invalidConfig: { + region: '', + }, + users: [ + { email: 'user1@example.com', name: 'User 1' }, + { email: 'user2@example.com', name: 'User 2' }, + ], +}; +``` + +### Test Helpers +```typescript +// ✅ GOOD - Create reusable test utilities +export function createMockConfig(overrides?: Partial): Config { + return { + region: 'us', + timeout: 30000, + ...overrides, + }; +} + +export function createMockService( + config: Config = createMockConfig() +): ConfigService { + return new ConfigService(config); +} +``` + +## Coverage + +### Coverage Goals +- **Team aspiration**: 80% minimum coverage +- **Current enforcement**: Applied consistently across packages +- **Focus areas**: Critical business logic and error paths + +### Coverage Reporting +```bash +# Run tests with coverage +pnpm test:coverage + +# Coverage reports generated in: +# - coverage/index.html (HTML report) +# - coverage/coverage-summary.json (JSON report) +``` + +## Critical Testing Rules + +- **No real external calls** - Mock all dependencies +- **Test both success and failure paths** - Cover error scenarios completely +- **One assertion per test** - Focus each test on single behavior +- **Use descriptive test names** - Test name should explain what's tested +- **Arrange-Act-Assert** - Follow AAA pattern consistently +- **Test command validation** - Verify flag validation and error messages +- **Clean up after tests** - Restore any mocked state + +## Best Practices + +### Test Organization +```typescript +// ✅ GOOD - Organize related tests +describe('AuthCommand', () => { + describe('login', () => { + it('should authenticate user'); + it('should save token'); + }); + + describe('logout', () => { + it('should clear token'); + it('should reset config'); + }); +}); +``` + +### Async Test Patterns +```typescript +// ✅ GOOD - Handle async operations properly +it('should complete async operation', async () => { + const promise = service.asyncMethod(); + expect(promise).to.be.instanceof(Promise); + + const result = await promise; + expect(result).to.equal('success'); +}); +``` + +### Isolation +```typescript +// ✅ GOOD - Ensure test isolation +describe('ConfigService', () => { + let service: ConfigService; + + beforeEach(() => { + service = new ConfigService(); + }); + + afterEach(() => { + // Clean up resources + }); +}); +``` diff --git a/.cursor/rules/typescript.mdc b/.cursor/rules/typescript.mdc new file mode 100644 index 0000000000..ea4d82a265 --- /dev/null +++ b/.cursor/rules/typescript.mdc @@ -0,0 +1,246 @@ +--- +description: 'TypeScript strict mode standards and naming conventions' +globs: ['**/*.ts', '**/*.tsx'] +alwaysApply: false +--- + +# TypeScript Standards + +## Configuration + +### Standard Configuration (All Packages) +```json +{ + "compilerOptions": { + "declaration": true, + "importHelpers": true, + "module": "commonjs", + "outDir": "lib", + "rootDir": "src", + "strict": false, // Relaxed for compatibility + "target": "es2017", + "sourceMap": false, + "allowJs": true, // Mixed JS/TS support + "skipLibCheck": true, + "esModuleInterop": true + }, + "include": ["src/**/*"] +} +``` + +### Root Configuration +```json +// tsconfig.json - Baseline configuration +{ + "compilerOptions": { + "strict": false, + "module": "commonjs", + "target": "es2017", + "declaration": true, + "outDir": "lib", + "rootDir": "src" + } +} +``` + +## Naming Conventions (Actual Usage) + +### Files +- **Primary pattern**: `kebab-case.ts` (e.g., `base-command.ts`, `config-handler.ts`) +- **Single-word modules**: `index.ts`, `types.ts` +- **Commands**: Follow OCLIF topic structure (`cm/auth/login.ts`, `cm/config/region.ts`) + +### Classes +```typescript +// ✅ GOOD - PascalCase for classes +export default class ConfigCommand extends Command { } +export class AuthService { } +export class ValidationError extends Error { } +``` + +### Functions and Methods +```typescript +// ✅ GOOD - camelCase for functions +export async function loadConfig(): Promise { } +async validateInput(input: string): Promise { } +createCommandContext(): CommandContext { } +``` + +### Constants +```typescript +// ✅ GOOD - SCREAMING_SNAKE_CASE for constants +const DEFAULT_REGION = 'us'; +const MAX_RETRIES = 3; +const API_BASE_URL = 'https://api.contentstack.io'; +``` + +### Interfaces and Types +```typescript +// ✅ GOOD - PascalCase for types +export interface CommandConfig { + region: string; + alias?: string; +} + +export type CommandResult = { + success: boolean; + message?: string; +}; +``` + +## Import/Export Patterns + +### ES Modules (Preferred) +```typescript +// ✅ GOOD - ES import/export syntax +import { Command } from '@oclif/core'; +import type { CommandConfig } from '../types'; +import { loadConfig } from '../utils'; + +export default class ConfigCommand extends Command { } +export { CommandConfig }; +``` + +### Default Exports +```typescript +// ✅ GOOD - Default export for commands and main classes +export default class ConfigCommand extends Command { } +``` + +### Named Exports +```typescript +// ✅ GOOD - Named exports for utilities and types +export async function delay(ms: number): Promise { } +export interface CommandOptions { } +export type ActionResult = 'success' | 'failure'; +``` + +## Type Definitions + +### Local Types +```typescript +// ✅ GOOD - Define types close to usage +export interface AuthOptions { + email: string; + password: string; + token?: string; +} + +export type ConfigResult = { + success: boolean; + config?: Record; +}; +``` + +### Type Organization +```typescript +// ✅ GOOD - Organize types in dedicated files +// src/types/index.ts +export interface CommandConfig { } +export interface AuthConfig { } +export type ConfigValue = string | number | boolean; +``` + +## Null Safety + +### Function Return Types +```typescript +// ✅ GOOD - Explicit return types +export async function getConfig(): Promise { + return await this.loadFromFile(); +} + +export function createDefaults(): CommandConfig { + return { + region: 'us', + timeout: 30000, + }; +} +``` + +### Null/Undefined Handling +```typescript +// ✅ GOOD - Handle null/undefined explicitly +function processConfig(config: CommandConfig | null): void { + if (!config) { + throw new Error('Configuration is required'); + } + // Process config safely +} +``` + +## Error Handling Types + +### Custom Error Classes +```typescript +// ✅ GOOD - Typed error classes +export class ValidationError extends Error { + constructor( + message: string, + public readonly code?: string + ) { + super(message); + this.name = 'ValidationError'; + } +} +``` + +### Error Union Types +```typescript +// ✅ GOOD - Model expected errors +type AuthResult = { + success: true; + data: T; +} | { + success: false; + error: string; +}; +``` + +## Strict Mode Adoption + +### Current Status +- Most packages use `strict: false` for compatibility +- Gradual migration path available +- Team working toward stricter TypeScript + +### Gradual Adoption +```typescript +// ✅ ACCEPTABLE - Comments for known issues +// TODO: Fix type issues in legacy code +const legacyData = unknownData as unknown; +``` + +## Package-Specific Patterns + +### Command Packages (auth, config) +- Extend `@oclif/core` Command +- Define command flags with `static flags` +- Use @oclif/core flag utilities +- Define command-specific types + +### Library Packages (command, utilities) +- No OCLIF dependencies +- Pure TypeScript interfaces +- Consumed by command packages +- Focus on type safety for exports + +### Main Package (contentstack) +- Aggregates command plugins +- May have common types +- Shared interfaces for plugin integration + +## Export Patterns + +### Package Exports (lib/index.js) +```typescript +// ✅ GOOD - Barrel exports for libraries +export { Command } from './command'; +export { loadConfig } from './config'; +export type { CommandConfig, AuthOptions } from './types'; +``` + +### Entry Points +- Libraries export from `lib/index.js` +- Commands export directly as default classes +- Type definitions included via `types` field in package.json