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
119 changes: 119 additions & 0 deletions .cursor/rules/clean-code.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
description: Standards for maintaining clean, readable, and maintainable code in the repository.
globs: src/**/*.ts
alwaysApply: false
---
# Clean Code Standards

Standards for maintaining clean, readable, and maintainable code in the repository.

<rule>
name: remove_unused_code
description: Always remove unused code after refactoring to maintain a clean codebase

filters:
- type: path
pattern: "^src/.*\\.ts$"

actions:
- type: suggest
message: |
After refactoring, always remove unused code to maintain a clean and maintainable codebase:

1. Remove unused:
- Variables, parameters, and function arguments
- Functions, methods, and classes
- Imports and exports
- Properties in interfaces and types
- Commented-out code blocks

2. Benefits of removing unused code:
- Reduces cognitive load when reading code
- Prevents confusion about which code paths are actually used
- Improves maintainability by reducing the surface area of the codebase
- Makes the codebase easier to understand for new contributors
- Prevents "dead" code from being accidentally reactivated

3. Tools to help identify unused code:
- TypeScript compiler with `noUnusedLocals` and `noUnusedParameters` flags
- ESLint with rules like `no-unused-vars` and `no-dead-code`
- IDE features that gray out unused code
- Code coverage tools to identify untested (potentially unused) code paths

4. When refactoring:
- Don't comment out old code - delete it (git history preserves it)
- Remove any code paths that are no longer reachable
- Delete any functions that are no longer called
- Remove any parameters that are no longer used
- Clean up imports that are no longer needed

examples:
- input: |
import { parseJson, formatJson, validateJson } from './utils';

function processData(data: string, options: { validate: boolean }): object {
// Old implementation
// const parsed = JSON.parse(data);
// return parsed;

const parsed = parseJson(data);

// We might need validation later
// if (options.validate) {
// validateJson(parsed);
// }

return parsed;
}
output: |
import { parseJson } from './utils';

function processData(data: string): object {
const parsed = parseJson(data);
return parsed;
}

- input: |
class DataProcessor {
private cache: Map<string, any> = new Map();
private logger: Logger;
private config: Config;

constructor(logger: Logger, config: Config) {
this.logger = logger;
this.config = config;
}

process(data: string): object {
const result = JSON.parse(data);
return result;
}

// Old method, no longer used after refactoring
// cacheResult(key: string, data: any): void {
// this.cache.set(key, data);
// this.logger.debug(`Cached data for key: ${key}`);
// }
}
output: |
class DataProcessor {
private logger: Logger;

constructor(logger: Logger) {
this.logger = logger;
}

process(data: string): object {
const result = JSON.parse(data);
return result;
}
}

metadata:
priority: high
version: 1.0
tags:
- clean-code
- refactoring
- best-practices
</rule>
111 changes: 111 additions & 0 deletions .cursor/rules/file-utils.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
description: Standards for using file utilities in the StackOne repository
globs: *.ts
alwaysApply: false
---
# File Utilities Standards

Standards for using file utilities in the StackOne repository.

<rule>
name: file_utils_standards
description: Standards for using file utilities from the file.ts module instead of direct fs/path operations

filters:
- type: path
pattern: "^src/.*\\.ts$"

actions:
- type: suggest
message: |
When working with files and directories:

1. Use the file utilities from `src/utils/file.ts`:
- Import the required utilities: `import { ... } from './utils/file'`
- Do not use fs/path modules directly unless absolutely necessary

2. Available utilities:
- `isBase64(str)`: Check if a string is base64 encoded
- `isValidFilePath(filePath)`: Check if a file path is valid and the file exists
- `readFileAsBase64(filePath)`: Read a file and return its contents as a base64 string
- `extractFileInfo(filePath)`: Extract file name and extension from a path
- `directoryExists(dirPath)`: Check if a directory exists
- `listFilesInDirectory(dirPath, filter?)`: List files in a directory with optional filtering
- `readJsonFile<T>(filePath)`: Read and parse a JSON file with type safety
- `getFileNameWithoutExtension(filePath)`: Get file name without extension
- `joinPaths(...segments)`: Join path segments safely

3. Benefits of using these utilities:
- Consistent error handling
- Type safety
- Centralized file operations
- Easier testing and mocking

examples:
- input: |
import fs from 'node:fs';
import path from 'node:path';

function processJsonFile(filePath: string) {
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
const data = JSON.parse(content);
return data;
}
throw new Error(`File not found: ${filePath}`);
}
output: |
import { isValidFilePath, readJsonFile } from '../utils/file';

function processJsonFile<T>(filePath: string): T {
if (isValidFilePath(filePath)) {
return readJsonFile<T>(filePath);
}
throw new Error(`File not found: ${filePath}`);
}

- input: |
import * as fs from 'node:fs';
import * as path from 'node:path';

function getFilesInDirectory(dirPath: string) {
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
return fs.readdirSync(dirPath).filter(file => file.endsWith('.json'));
}
return [];
}
output: |
import { directoryExists, listFilesInDirectory } from '../utils/file';

function getFilesInDirectory(dirPath: string): string[] {
if (directoryExists(dirPath)) {
return listFilesInDirectory(dirPath, file => file.endsWith('.json'));
}
return [];
}

- input: |
import fs from 'node:fs';
import path from 'node:path';

function getFileNameWithoutExt(filePath: string): string {
const fileName = path.basename(filePath);
const dotIndex = fileName.lastIndexOf('.');
return dotIndex === -1 ? fileName : fileName.substring(0, dotIndex);
}
output: |
import { getFileNameWithoutExtension } from '../utils/file';

function getFileNameWithoutExt(filePath: string): string {
return getFileNameWithoutExtension(filePath);
}

metadata:
priority: high
version: 1.0
tags:
- files
- directories
- utilities
- standards
</rule>
110 changes: 110 additions & 0 deletions .cursor/rules/json-schema-handling.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
description: Standards for working with JSON Schema types in the repository.
globs: *.ts
alwaysApply: false
---
# JSON Schema Handling

Standards for working with JSON Schema types in the repository.

<rule>
name: json_schema_handling
description: Standards for properly handling JSON Schema types to avoid type errors

filters:
- type: path
pattern: "^src/.*\\.ts$"

actions:
- type: suggest
message: |
When working with JSON Schema types, follow these guidelines to avoid type errors:

1. Understanding JSONSchema7Definition type:
- `JSONSchema7Definition` is a union type that can be either a `JSONSchema7` object or a boolean
- It does NOT accept `undefined` as a valid value
- Setting a property to `undefined` will cause a type error

2. Handling the conflict between TypeScript types and linter rules:
- The TypeScript type system doesn't allow setting a `JSONSchema7Definition` property to `undefined`
- However, linters like Biome may prefer using `undefined` assignment over the `delete` operator for performance
- To satisfy both, use one of these approaches:

3. Recommended approaches for removing JSON Schema properties:
- Use type assertion when setting to undefined: `obj.properties['prop'] = undefined as unknown as JSONSchema7Definition`
- Create a new object without the property using destructuring: `const { propToRemove, ...rest } = obj.properties`
- Use a helper function that handles the type casting internally
- For complex objects, consider using a deep clone and filter approach

4. When modifying schema objects:
- Create a new object with spread syntax rather than modifying in place when possible
- Use proper type guards to ensure type safety
- Consider using a deep clone for complex nested schemas to avoid reference issues
- Always check if a property exists before attempting to modify it

examples:
- input: |
// Problematic: Type error with undefined, linter warning with delete
function removeSchemaProperty(schema: { properties: Record<string, JSONSchema7Definition> }): void {
// TypeScript error: Type 'undefined' is not assignable to type 'JSONSchema7Definition'
schema.properties['propertyToRemove'] = undefined;

// Linter warning: Avoid the delete operator which can impact performance
delete schema.properties['propertyToRemove'];
}
output: |
// Solution 1: Type assertion to satisfy TypeScript
function removeSchemaProperty(schema: { properties: Record<string, JSONSchema7Definition> }): void {
// Use type assertion to satisfy TypeScript while using undefined (preferred by linters)
schema.properties['propertyToRemove'] = undefined as unknown as JSONSchema7Definition;
}

// Solution 2: Create a new object without the property
function removeSchemaProperty(schema: { properties: Record<string, JSONSchema7Definition> }): { properties: Record<string, JSONSchema7Definition> } {
const { propertyToRemove, ...rest } = schema.properties;
return { ...schema, properties: rest };
}

// Solution 3: Helper function approach
function removeJsonSchemaProperty<T>(obj: Record<string, T>, key: string): void {
// This function encapsulates the type assertion
obj[key] = undefined as unknown as T;
}

function removeSchemaProperty(schema: { properties: Record<string, JSONSchema7Definition> }): void {
removeJsonSchemaProperty(schema.properties, 'propertyToRemove');
}

- input: |
// Incorrect: Not checking if properties exist
function processSchema(schema: JSONSchema7): void {
const requiredProps = schema.required;
requiredProps.forEach(prop => {
schema.properties[prop].description = 'This property is required';
});
}
output: |
// Correct: Checking if properties exist
function processSchema(schema: JSONSchema7): void {
if (!schema.required || !schema.properties) {
return;
}

schema.required.forEach(prop => {
if (schema.properties && prop in schema.properties) {
const propSchema = schema.properties[prop];
if (typeof propSchema === 'object' && propSchema !== null) {
propSchema.description = 'This property is required';
}
}
});
}

metadata:
priority: high
version: 1.0
tags:
- json-schema
- typescript
- type-safety
</rule>
Loading