# Lockness Deprecation System Graceful deprecation warnings for breaking changes. ## Overview Lockness provides a powerful deprecation system through the `@lockness/deprecation-contracts` package to: - Warn developers about deprecated features - Provide migration paths - Track deprecation usage in Devtools (when installed) - Plan for removal ## Installation ```bash deno task cli package:install deprecation-contracts ``` This will: - Add the package to your `deno.json` imports - Create environment variables in `.env` for configuration - Enable deprecation tracking throughout your application ### Optional: Devtools Integration For **visual tracking** of deprecations, install Lockness Devtools: ```bash deno task cli package:install devtools ``` When both packages are installed: - ✅ Deprecations appear in the Devtools dashboard (Logs panel) - ✅ Full stack traces for each deprecation - ✅ Package and version information - ✅ Timestamp and occurrence tracking - ✅ Quick navigation to source code The integration is **automatic** - no configuration needed. Without devtools, deprecations still work and are logged to the console. ## Basic Usage ### Mark as Deprecated ```typescript import { deprecated } from '@lockness/deprecation-contracts' @deprecated('Use NewClass instead', '2.0.0') export class OldClass { // Implementation } @deprecated('Use newMethod() instead', '2.0.0') oldMethod() { // Old implementation } ``` ### Runtime Warnings When deprecated code is used: ``` ⚠️ DEPRECATED: OldClass is deprecated and will be removed in v2.0.0 Use NewClass instead at src/service/user_service.ts:15 ``` ## Decorator Usage ### Class Deprecation ```typescript import { deprecated } from '@lockness/deprecation-contracts' @deprecated('Use UserRepository instead', '2.0.0') export class UserService { // Class marked as deprecated } ``` ### Method Deprecation ```typescript export class UserRepository { @deprecated('Use findById() instead', '2.0.0') getUser(id: number) { return this.findById(id) } findById(id: number) { // New implementation } } ``` ### Property Deprecation ```typescript export class Config { @deprecated('Use apiEndpoint instead', '2.0.0') apiUrl: string apiEndpoint: string } ``` ## Configuration Configure deprecation behavior via environment variables: ```bash # .env STRICT_DEPRECATIONS=false # Set to 'true' to throw errors instead of warnings IGNORE_DEPRECATIONS=false # Set to 'true' to completely disable deprecations ``` **Note:** When `@lockness/devtools` is installed, all deprecations are automatically sent to the Devtools collector in addition to console logging. ### Custom Collector If you need custom handling, you can register your own collector: ```typescript import { registerDeprecationCollector } from '@lockness/deprecation-contracts' registerDeprecationCollector({ addDeprecation(entry) { // Send to external logging service fetch('https://api.logging.com/deprecations', { method: 'POST', body: JSON.stringify(entry), }) }, }) ``` ## Warning Levels ### Soft Deprecation (Warning) ```typescript @deprecated('Feature will be removed', '2.0.0', 'warning') export class OldFeature {} // Output: ⚠️ Warning: Feature deprecated ``` ### Hard Deprecation (Error) ```typescript @deprecated('Feature already removed', '1.5.0', 'error') export class RemovedFeature {} // Output: ❌ Error: Feature is deprecated and should not be used // Throws error in strict mode ``` ## Migration Guides ### With Documentation Link ```typescript @deprecated( 'Use new authentication system', '2.0.0', 'warning', 'https://docs.lockness.dev/migration/auth' ) export class LegacyAuth {} // Output includes link to migration guide ``` ### Inline Migration Example ```typescript @deprecated(` Use new API: Before: const user = userService.getUser(id) After: const user = await userRepository.findById(id) `, '2.0.0') export class UserService {} ``` ## Tracking ### Count Usage ```typescript import { getDeprecationStats } from '@lockness/deprecation-contracts' // Get usage statistics const stats = getDeprecationStats() console.log(stats) // { // 'OldClass': { count: 15, locations: [...] }, // 'oldMethod': { count: 8, locations: [...] } // } ``` ### Log to File ```typescript configureDeprecation({ track: true, onDeprecation: (message, location) => { Deno.writeTextFile( 'deprecations.log', `${new Date().toISOString()} - ${message} at ${location}\n`, { append: true } ) }, }) ``` ## Conditional Deprecation ### Version-Based ```typescript @deprecated( 'Removed in v2.0', '2.0.0', Deno.env.get('APP_VERSION') >= '2.0.0' ? 'error' : 'warning' ) export class LegacyFeature {} ``` ### Environment-Based ```typescript const severity = Deno.env.get('APP_ENV') === 'production' ? 'error' : 'warning' @deprecated('Use new implementation', '2.0.0', severity) export class OldImplementation {} ``` ## Custom Deprecation Handler ```typescript import { DeprecationHandler } from '@lockness/deprecation-contracts' class CustomDeprecationHandler extends DeprecationHandler { handle(deprecation: Deprecation) { // Send to logging service fetch('https://api.logging.com/deprecations', { method: 'POST', body: JSON.stringify({ message: deprecation.message, location: deprecation.location, timestamp: Date.now(), }), }) // Also log locally console.warn(`⚠️ ${deprecation.message}`) } } configureDeprecation({ handler: new CustomDeprecationHandler(), }) ``` ## Best Practices ### Use Devtools in Development For Lockness applications, always use devtools to track deprecations: ```bash # Install both packages deno task cli package:install deprecation-contracts deno task cli package:install devtools ``` Benefits: - Visual dashboard showing all deprecations - Stack traces for quick debugging - Historical tracking of deprecation usage - No manual logging configuration needed ### Clear Migration Path ```typescript @deprecated(` DEPRECATED: UserService.getUsers() Migration: 1. Replace UserService with UserRepository 2. Change getUsers() to findAll() 3. Update imports Before: const users = userService.getUsers() After: const users = await userRepository.findAll() `, '2.0.0') export class UserService {} ``` ### Gradual Deprecation ```typescript // Phase 1: Soft warning (v1.5) @deprecated('Feature will change', '2.0.0', 'warning') // Phase 2: Hard warning (v1.8) @deprecated('Feature will be removed soon', '2.0.0', 'error') // Phase 3: Remove (v2.0) // Delete the class/method ``` ### Alternative API ```typescript export class UserRepository { // Deprecated method @deprecated('Use findById() instead', '2.0.0') getUser(id: number) { // Internally calls new method return this.findById(id) } // New method findById(id: number) { // New implementation } } ``` ## CLI Integration ### Check for Deprecations ```bash deno task cli deprecation:check ``` Output: ``` Found 3 deprecated features in use: ❌ UserService.getUser() Used at: src/controller/user_controller.tsx:15 Migration: Use UserRepository.findById() instead ⚠️ OldAuthMiddleware Used at: src/kernel.tsx:23 Migration: Use AuthMiddleware from @lockness/auth ⚠️ legacyConfig.apiUrl Used at: src/service/api_service.ts:8 Migration: Use config.apiEndpoint instead ``` ### Generate Report ```bash deno task cli deprecation:report --output=deprecations.json ``` ## Testing ### Suppress Warnings in Tests ```typescript import { silenceDeprecations } from '@lockness/deprecation-contracts' Deno.test('legacy feature', () => { silenceDeprecations(() => { // Use deprecated code without warnings const result = legacyFeature() assertEquals(result, expected) }) }) ``` ### Assert Deprecation ```typescript import { assertDeprecated } from '@lockness/deprecation-contracts' Deno.test('should warn about deprecation', () => { assertDeprecated(() => { new OldClass() }, 'Use NewClass instead') }) ``` ## Examples ### Controller Method ```typescript @Controller('/users') export class UserController { @Get('/list') @deprecated('Use GET /users instead', '2.0.0') list(c: Context) { return c.redirect('/users') } @Get('/') index(c: Context) { // New implementation } } ``` ### Configuration ```typescript export class AppConfig { @deprecated('Use database.url instead', '2.0.0') get databaseUrl() { return this.database.url } database = { url: Deno.env.get('DATABASE_URL')!, } } ``` ### Service ```typescript @Service() export class NotificationService { @deprecated('Use sendEmail() with template parameter', '2.0.0') sendWelcomeEmail(email: string) { return this.sendEmail(email, 'welcome') } sendEmail(email: string, template: string) { // New implementation } } ``` ## Roadmap Planning ### Version Timeline ```typescript // v1.5 - Deprecate @deprecated('Will be removed in v2.0', '2.0.0', 'warning') // v1.8 - Stricter warning @deprecated('Will be removed in v2.0', '2.0.0', 'error') // v2.0 - Remove // Delete code ``` ### Breaking Changes Document ```typescript // BREAKING_CHANGES.md /** * v2.0.0 Breaking Changes * * 1. UserService removed * - Use: UserRepository * - Migration: See docs/migration/v2.md * * 2. Auth middleware changed * - Use: @lockness/auth * - Migration: See docs/migration/auth.md * * 3. Config API changed * - Use: config.database.url * - Migration: Update all references */ ``` ## Integration with CI/CD ### Fail on Deprecations ```bash # .github/workflows/ci.yml - name: Check deprecations run: | deno task cli deprecation:check --strict ``` ### Track Over Time ```bash # Generate report deno task cli deprecation:report --output=deprecations-${VERSION}.json # Compare with previous version diff deprecations-v1.5.0.json deprecations-v1.6.0.json ``` ## Production Behavior ```typescript // In production, deprecations are typically silent configureDeprecation({ mode: Deno.env.get('APP_ENV') === 'production' ? 'off' : 'development', }) // Or log to monitoring service only configureDeprecation({ mode: 'production', onDeprecation: (message, location) => { // Send to error tracking (Sentry, DataDog, etc.) errorTracker.logDeprecation({ message, location, timestamp: Date.now(), }) }, }) ```