diff --git a/docs/sync-and-op-log/supersync-encryption-architecture.md b/docs/sync-and-op-log/supersync-encryption-architecture.md index c25aff6d58..50c9a4bb75 100644 --- a/docs/sync-and-op-log/supersync-encryption-architecture.md +++ b/docs/sync-and-op-log/supersync-encryption-architecture.md @@ -227,13 +227,13 @@ privateCfg: { ## Security Properties -| Property | Guarantee | -| ------------------- | ---------------------------------------------- | -| **Confidentiality** | Server cannot read operation payloads | +| Property | Guarantee | +| ------------------- | ----------------------------------------------- | +| **Confidentiality** | Server cannot read operation payloads | | **Integrity** | GCM auth tag detects tampering of the _payload_ | -| **Key Security** | Argon2id makes brute-force expensive | -| **Forward Secrecy** | Each operation uses random IV | -| **Wrong Password** | Decryption fails, operation rejected | +| **Key Security** | Argon2id makes brute-force expensive | +| **Forward Secrecy** | Each operation uses random IV | +| **Wrong Password** | Decryption fails, operation rejected | > **Integrity scope (important).** Only `op.payload` is encrypted and covered by > the AES-GCM authentication tag. Every other operation field — `actionType`, @@ -245,7 +245,7 @@ privateCfg: { > tamper vectors: > > - **Plaintext-injection downgrade:** a forged op with `isPayloadEncrypted=false` -> would skip decryption *and* the payload check and be applied as-is — arbitrary +> would skip decryption _and_ the payload check and be applied as-is — arbitrary > op forgery on an encryption-mandatory client. `assertOpsEncryptedWhenExpected` > rejects any inbound plaintext op (download + piggyback) when encryption is > **enabled in config** (`isEncryptionMandatory && isEncryptionEnabled()` — @@ -254,8 +254,8 @@ privateCfg: { > re-uploads all data encrypted, so no legitimate plaintext op remains — this > rests on the server contract that `deleteAllData()` removes every downloadable > plaintext op. This is the SuperSync op-level twin of the file-based GHSA-vrc7 -> download guard and the GHSA-9544 *upload* guard. -> - **LWW `entityId` retarget:** the client rejects an *encrypted* LWW-update op +> download guard and the GHSA-9544 _upload_ guard. +> - **LWW `entityId` retarget:** the client rejects an _encrypted_ LWW-update op > whose authenticated `payload.id` does not equal `op.entityId` > (`verify-decrypted-op-integrity.ts`). > @@ -270,7 +270,7 @@ privateCfg: { > authenticate it. > > Known limitation: a peer running an app version that predates the GHSA-9544 -> *upload* guard can still push plaintext ops; a keyed client then fails closed +> _upload_ guard can still push plaintext ops; a keyed client then fails closed > here with the tamper message. Recovery is to update the old peer. > > Full protection — binding the metadata (and the encryption flag) as GCM AAD diff --git a/scripts/fix-duplicate-imports.ts b/scripts/fix-duplicate-imports.ts deleted file mode 100755 index 9ed3110388..0000000000 --- a/scripts/fix-duplicate-imports.ts +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env ts-node - -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; - -// Pattern to find duplicate imports -const findDuplicateImports = (content: string): string[] => { - const importRegex = /^import\s+.*?;$/gm; - const imports = content.match(importRegex) || []; - const seen = new Set(); - const duplicates: string[] = []; - - for (const imp of imports) { - const normalized = imp.trim(); - if (seen.has(normalized)) { - duplicates.push(normalized); - } else { - seen.add(normalized); - } - } - - return duplicates; -}; - -// Remove duplicate imports from content -const removeDuplicateImports = (content: string): string => { - const lines = content.split('\n'); - const seenImports = new Set(); - const resultLines: string[] = []; - - for (const line of lines) { - const trimmedLine = line.trim(); - - // Check if it's an import statement - if (trimmedLine.startsWith('import ') && trimmedLine.endsWith(';')) { - if (seenImports.has(trimmedLine)) { - // Skip duplicate import - continue; - } - seenImports.add(trimmedLine); - } - - resultLines.push(line); - } - - return resultLines.join('\n'); -}; - -function processFile(filePath: string): boolean { - try { - const content = fs.readFileSync(filePath, 'utf8'); - const duplicates = findDuplicateImports(content); - - if (duplicates.length > 0) { - console.log( - `Found ${duplicates.length} duplicate imports in ${path.relative(process.cwd(), filePath)}:`, - ); - duplicates.forEach((dup) => console.log(` - ${dup}`)); - - const fixedContent = removeDuplicateImports(content); - fs.writeFileSync(filePath, fixedContent, 'utf8'); - return true; - } - - return false; - } catch (error) { - console.error(`Error processing ${filePath}:`, error); - return false; - } -} - -function main() { - console.log('Searching for duplicate imports...\n'); - - const files = glob.sync('src/**/*.ts', { - ignore: ['**/node_modules/**', '**/dist/**', '**/build/**'], - absolute: true, - }); - - let fixedCount = 0; - - for (const file of files) { - if (processFile(file)) { - fixedCount++; - } - } - - console.log(`\nFixed duplicate imports in ${fixedCount} files.`); -} - -main(); diff --git a/scripts/log-migration-helper.test.cjs b/scripts/log-migration-helper.test.cjs deleted file mode 100644 index ebe1a963e4..0000000000 --- a/scripts/log-migration-helper.test.cjs +++ /dev/null @@ -1,55 +0,0 @@ -require('ts-node/register/transpile-only'); - -const assert = require('node:assert/strict'); -const test = require('node:test'); -const { migrateLogContent } = require('./log-migration-helper.ts'); - -test('migrates Log calls and updates the import for the target logger', () => { - const input = [ - "import { Log, OtherLog } from '../core/log';", - '', - "Log.log('a');", - "Log.err('b');", - 'OtherLog.log();', - '', - ].join('\n'); - - const result = migrateLogContent(input, 'PluginLog'); - - assert.equal(result.changes, 2); - assert.equal( - result.content, - [ - "import { OtherLog, PluginLog } from '../core/log';", - '', - "PluginLog.log('a');", - "PluginLog.err('b');", - 'OtherLog.log();', - '', - ].join('\n'), - ); -}); - -test('keeps the Log import when non-call Log references remain', () => { - const input = [ - "import { Log } from '../core/log';", - '', - 'const logger = Log;', - "Log.info('a');", - '', - ].join('\n'); - - const result = migrateLogContent(input, 'IssueLog'); - - assert.equal(result.changes, 1); - assert.equal( - result.content, - [ - "import { Log, IssueLog } from '../core/log';", - '', - 'const logger = Log;', - "IssueLog.info('a');", - '', - ].join('\n'), - ); -}); diff --git a/scripts/log-migration-helper.ts b/scripts/log-migration-helper.ts deleted file mode 100644 index 7bd8a5128e..0000000000 --- a/scripts/log-migration-helper.ts +++ /dev/null @@ -1,171 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; - -interface Replacement { - pattern: RegExp; - replacement: string; -} - -export interface LogMigrationConfig { - description: string; - fileLabel: string; - globPattern: string; - targetLogName: string; - ignore?: string[]; -} - -export interface MigrationResult { - content: string; - changes: number; -} - -export interface FileMigrationResult { - modified: boolean; - changes: number; -} - -const DEFAULT_IGNORE = ['**/*.spec.ts', '**/node_modules/**']; -const LOG_METHODS = ['log', 'err', 'info', 'debug', 'verbose', 'critical']; - -const createReplacements = (targetLogName: string): Replacement[] => - LOG_METHODS.map((method) => ({ - pattern: new RegExp(`\\bLog\\.${method}\\(`, 'g'), - replacement: `${targetLogName}.${method}(`, - })); - -const getTargetLogImportRegex = (targetLogName: string): RegExp => - new RegExp( - `import\\s*{[^}]*\\b${targetLogName}\\b[^}]*}\\s*from\\s*['"][^'"]*\\/log['"]`, - ); - -const LOG_IMPORT_REGEX = /import\s*{([^}]*\bLog\b[^}]*)}\s*from\s*(['"][^'"]*\/log['"])/; - -const updateImports = ( - content: string, - targetLogName: string, - replacements: Replacement[], -): string => { - if (getTargetLogImportRegex(targetLogName).test(content)) { - return content; - } - - const match = content.match(LOG_IMPORT_REGEX); - if (!match) { - return content; - } - - const [fullMatch, imports, importPath] = match; - const importList = imports.split(',').map((s) => s.trim()); - - if (!importList.includes(targetLogName)) { - importList.push(targetLogName); - } - - let tempContent = content; - for (const { pattern, replacement } of replacements) { - tempContent = tempContent.replace(pattern, replacement); - } - - tempContent = tempContent.replace(LOG_IMPORT_REGEX, ''); - - if (!/\bLog\b/.test(tempContent)) { - const logIndex = importList.indexOf('Log'); - if (logIndex > -1) { - importList.splice(logIndex, 1); - } - } - - return content.replace( - fullMatch, - `import { ${importList.join(', ')} } from ${importPath}`, - ); -}; - -export const migrateLogContent = ( - content: string, - targetLogName: string, -): MigrationResult => { - const replacements = createReplacements(targetLogName); - let nextContent = content; - let changeCount = 0; - - for (const { pattern, replacement } of replacements) { - const matches = nextContent.match(pattern); - if (matches) { - changeCount += matches.length; - nextContent = nextContent.replace(pattern, replacement); - } - } - - if (changeCount > 0) { - nextContent = updateImports(nextContent, targetLogName, replacements); - } - - return { - content: nextContent, - changes: changeCount, - }; -}; - -export const migrateLogFile = ( - filePath: string, - targetLogName: string, - dryRun: boolean = false, -): FileMigrationResult => { - try { - const originalContent = fs.readFileSync(filePath, 'utf8'); - const { content, changes } = migrateLogContent(originalContent, targetLogName); - const modified = content !== originalContent; - - if (modified && !dryRun) { - fs.writeFileSync(filePath, content, 'utf8'); - } - - return { modified, changes }; - } catch (error) { - console.error(`Error processing ${filePath}:`, error); - return { modified: false, changes: 0 }; - } -}; - -export const runLogMigration = (config: LogMigrationConfig): void => { - const dryRun = process.argv.includes('--dry-run'); - - console.log(`${config.description}\n`); - if (dryRun) { - console.log('Running in DRY RUN mode - no files will be modified\n'); - } - - const files = glob.sync(config.globPattern, { - ignore: config.ignore || DEFAULT_IGNORE, - absolute: true, - }); - - console.log(`Found ${files.length} ${config.fileLabel}\n`); - - const modifiedFiles: { path: string; changes: number }[] = []; - let totalChanges = 0; - - for (const file of files) { - const result = migrateLogFile(file, config.targetLogName, dryRun); - if (result.modified) { - modifiedFiles.push({ path: file, changes: result.changes }); - totalChanges += result.changes; - } - } - - console.log('\nMigration complete!\n'); - console.log(`Total changes: ${totalChanges}`); - console.log(`${dryRun ? 'Would modify' : 'Modified'} ${modifiedFiles.length} files:\n`); - - modifiedFiles - .sort((a, b) => b.changes - a.changes) - .forEach(({ path: filePath, changes }) => { - console.log(` - ${path.relative(process.cwd(), filePath)} (${changes} changes)`); - }); - - if (modifiedFiles.length === 0) { - console.log(' No files needed modification.'); - } -}; diff --git a/scripts/migrate-console-to-log-force.ts b/scripts/migrate-console-to-log-force.ts deleted file mode 100755 index 40171c4a98..0000000000 --- a/scripts/migrate-console-to-log-force.ts +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env ts-node - -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; - -interface Replacement { - pattern: RegExp; - replacement: string; - logMethod: string; -} - -const replacements: Replacement[] = [ - { pattern: /\bconsole\.log\(/g, replacement: 'Log.log(', logMethod: 'log' }, - { pattern: /\bconsole\.info\(/g, replacement: 'Log.info(', logMethod: 'info' }, - { pattern: /\bconsole\.error\(/g, replacement: 'Log.err(', logMethod: 'err' }, - { pattern: /\bconsole\.warn\(/g, replacement: 'Log.err(', logMethod: 'err' }, - { pattern: /\bconsole\.debug\(/g, replacement: 'Log.debug(', logMethod: 'debug' }, -]; - -// Files to exclude -const excludePatterns = [ - '**/node_modules/**', - '**/dist/**', - '**/build/**', - '**/*.spec.ts', - '**/core/log.ts', - '**/scripts/migrate-console-to-log*.ts', - '**/e2e/**', - '**/coverage/**', - '**/.angular/**', -]; - -function calculateImportPath(filePath: string): string { - const fileDir = path.dirname(filePath); - const logPath = path.join(__dirname, '../src/app/core/log'); - let relativePath = path.relative(fileDir, logPath).replace(/\\/g, '/'); - - // Remove .ts extension if present - relativePath = relativePath.replace(/\.ts$/, ''); - - // Ensure it starts with ./ or ../ - if (!relativePath.startsWith('.')) { - relativePath = './' + relativePath; - } - - return relativePath; -} - -function hasLogImport(content: string): boolean { - // Check if there's already a Log import from core/log - return /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"][^'"]*\/core\/log['"]/.test(content); -} - -function addLogImport(content: string, importPath: string): string { - // Find the last import statement - const importRegex = /^import\s+.*?;$/gm; - const imports = content.match(importRegex); - - if (imports && imports.length > 0) { - const lastImport = imports[imports.length - 1]; - const lastImportIndex = content.lastIndexOf(lastImport); - const insertPosition = lastImportIndex + lastImport.length; - - return ( - content.slice(0, insertPosition) + - `\nimport { Log } from '${importPath}';` + - content.slice(insertPosition) - ); - } else { - // No imports found, add at the beginning - return `import { Log } from '${importPath}';\n\n` + content; - } -} - -function processFile( - filePath: string, - dryRun: boolean = false, -): { modified: boolean; changes: number } { - try { - let content = fs.readFileSync(filePath, 'utf8'); - const originalContent = content; - let changeCount = 0; - - // Apply replacements - this will replace even in comments, which is what we want - for (const { pattern, replacement } of replacements) { - const matches = content.match(pattern); - if (matches) { - changeCount += matches.length; - content = content.replace(pattern, replacement); - } - } - - // If we made changes and don't have the correct Log import, add it - if (changeCount > 0 && !hasLogImport(content)) { - const importPath = calculateImportPath(filePath); - content = addLogImport(content, importPath); - } - - const modified = content !== originalContent; - - if (modified && !dryRun) { - fs.writeFileSync(filePath, content, 'utf8'); - } - - return { modified, changes: changeCount }; - } catch (error) { - console.error(`Error processing ${filePath}:`, error); - return { modified: false, changes: 0 }; - } -} - -function main() { - const args = process.argv.slice(2); - const dryRun = args.includes('--dry-run'); - - console.log('Starting FORCED console to Log migration...'); - console.log('This will replace ALL console.* calls, including those in comments.'); - if (dryRun) { - console.log('Running in DRY RUN mode - no files will be modified\n'); - } - - // Find all TypeScript files - const files = glob.sync('src/**/*.ts', { - ignore: excludePatterns, - absolute: true, - }); - - console.log(`Found ${files.length} TypeScript files to check\n`); - - const modifiedFiles: { path: string; changes: number }[] = []; - const stats = { - total: 0, - log: 0, - info: 0, - error: 0, - warn: 0, - debug: 0, - }; - - for (const file of files) { - const content = fs.readFileSync(file, 'utf8'); - - // Count occurrences before processing (with word boundary) - const logCount = (content.match(/\bconsole\.log\(/g) || []).length; - const infoCount = (content.match(/\bconsole\.info\(/g) || []).length; - const errorCount = (content.match(/\bconsole\.error\(/g) || []).length; - const warnCount = (content.match(/\bconsole\.warn\(/g) || []).length; - const debugCount = (content.match(/\bconsole\.debug\(/g) || []).length; - - stats.log += logCount; - stats.info += infoCount; - stats.error += errorCount; - stats.warn += warnCount; - stats.debug += debugCount; - - const result = processFile(file, dryRun); - if (result.modified) { - modifiedFiles.push({ path: file, changes: result.changes }); - } - } - - stats.total = stats.log + stats.info + stats.error + stats.warn + stats.debug; - - console.log('\nMigration complete!\n'); - console.log('Statistics:'); - console.log(` Total console calls found: ${stats.total}`); - console.log(` - console.log: ${stats.log}`); - console.log(` - console.info: ${stats.info}`); - console.log(` - console.error: ${stats.error}`); - console.log(` - console.warn: ${stats.warn}`); - console.log(` - console.debug: ${stats.debug}`); - console.log( - `\n${dryRun ? 'Would modify' : 'Modified'} ${modifiedFiles.length} files:\n`, - ); - - modifiedFiles - .sort((a, b) => b.changes - a.changes) - .forEach(({ path: filePath, changes }) => { - console.log(` - ${path.relative(process.cwd(), filePath)} (${changes} changes)`); - }); - - if (modifiedFiles.length === 0) { - console.log(' No files needed modification.'); - } -} - -// Run the migration -main(); diff --git a/scripts/migrate-console-to-log.ts b/scripts/migrate-console-to-log.ts deleted file mode 100755 index 2d571a3836..0000000000 --- a/scripts/migrate-console-to-log.ts +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env ts-node - -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; - -interface Replacement { - pattern: RegExp; - replacement: string; - logMethod: string; -} - -const replacements: Replacement[] = [ - { pattern: /\bconsole\.log\(/g, replacement: 'Log.log(', logMethod: 'log' }, - { pattern: /\bconsole\.info\(/g, replacement: 'Log.info(', logMethod: 'info' }, - { pattern: /\bconsole\.error\(/g, replacement: 'Log.err(', logMethod: 'err' }, - { pattern: /\bconsole\.warn\(/g, replacement: 'Log.err(', logMethod: 'err' }, - { pattern: /\bconsole\.debug\(/g, replacement: 'Log.debug(', logMethod: 'debug' }, -]; - -// Files to exclude -const excludePatterns = [ - '**/node_modules/**', - '**/dist/**', - '**/build/**', - '**/*.spec.ts', - '**/core/log.ts', - '**/scripts/migrate-console-to-log.ts', - '**/e2e/**', - '**/coverage/**', - '**/.angular/**', -]; - -function calculateImportPath(filePath: string): string { - const fileDir = path.dirname(filePath); - const logPath = path.join(__dirname, '../src/app/core/log'); - let relativePath = path.relative(fileDir, logPath).replace(/\\/g, '/'); - - // Remove .ts extension if present - relativePath = relativePath.replace(/\.ts$/, ''); - - // Ensure it starts with ./ or ../ - if (!relativePath.startsWith('.')) { - relativePath = './' + relativePath; - } - - return relativePath; -} - -function hasLogImport(content: string): boolean { - // More flexible pattern that matches any Log import - return /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"].*['"]/.test(content); -} - -function addLogImport(content: string, importPath: string): string { - // Find the last import statement - const importRegex = /^import\s+.*?;$/gm; - const imports = content.match(importRegex); - - if (imports && imports.length > 0) { - const lastImport = imports[imports.length - 1]; - const lastImportIndex = content.lastIndexOf(lastImport); - const insertPosition = lastImportIndex + lastImport.length; - - return ( - content.slice(0, insertPosition) + - `\nimport { Log } from '${importPath}';` + - content.slice(insertPosition) - ); - } else { - // No imports found, add at the beginning - return `import { Log } from '${importPath}';\n\n` + content; - } -} - -function processFile(filePath: string, dryRun: boolean = false): boolean { - try { - let content = fs.readFileSync(filePath, 'utf8'); - const originalContent = content; - let hasChanges = false; - - // Check if file uses any console methods (including in comments) - const usesConsole = replacements.some((r) => r.pattern.test(content)); - - if (!usesConsole) { - return false; - } - - // Apply replacements - this will replace even in comments, which is what we want - for (const { pattern, replacement } of replacements) { - if (pattern.test(content)) { - content = content.replace(pattern, replacement); - hasChanges = true; - } - } - - if (hasChanges && !hasLogImport(content)) { - const importPath = calculateImportPath(filePath); - content = addLogImport(content, importPath); - } - - if (content !== originalContent) { - if (!dryRun) { - fs.writeFileSync(filePath, content, 'utf8'); - } - return true; - } - - return false; - } catch (error) { - console.error(`Error processing ${filePath}:`, error); - return false; - } -} - -function main() { - const args = process.argv.slice(2); - const dryRun = args.includes('--dry-run'); - - console.log('Starting console to Log migration...'); - if (dryRun) { - console.log('Running in DRY RUN mode - no files will be modified\n'); - } - - // Find all TypeScript files - const files = glob.sync('src/**/*.ts', { - ignore: excludePatterns, - absolute: true, - }); - - console.log(`Found ${files.length} TypeScript files to check\n`); - - const modifiedFiles: string[] = []; - const stats = { - total: 0, - log: 0, - info: 0, - error: 0, - warn: 0, - debug: 0, - }; - - for (const file of files) { - const content = fs.readFileSync(file, 'utf8'); - - // Count occurrences before processing (with word boundary) - stats.log += (content.match(/\bconsole\.log\(/g) || []).length; - stats.info += (content.match(/\bconsole\.info\(/g) || []).length; - stats.error += (content.match(/\bconsole\.error\(/g) || []).length; - stats.warn += (content.match(/\bconsole\.warn\(/g) || []).length; - stats.debug += (content.match(/\bconsole\.debug\(/g) || []).length; - - const willModify = processFile(file, dryRun); - if (willModify) { - modifiedFiles.push(file); - } - } - - stats.total = stats.log + stats.info + stats.error + stats.warn + stats.debug; - - console.log('\nMigration complete!\n'); - console.log('Statistics:'); - console.log(` Total console calls found: ${stats.total}`); - console.log(` - console.log: ${stats.log}`); - console.log(` - console.info: ${stats.info}`); - console.log(` - console.error: ${stats.error}`); - console.log(` - console.warn: ${stats.warn}`); - console.log(` - console.debug: ${stats.debug}`); - console.log(`\n${dryRun ? 'Would modify' : 'Modified'} ${modifiedFiles.length} files:`); - - modifiedFiles.forEach((file) => { - console.log(` - ${path.relative(process.cwd(), file)}`); - }); - - if (modifiedFiles.length === 0) { - console.log(' No files needed modification.'); - } -} - -// Run the migration -main(); diff --git a/scripts/migrate-to-droid-log.ts b/scripts/migrate-to-droid-log.ts deleted file mode 100755 index ba6fac19e6..0000000000 --- a/scripts/migrate-to-droid-log.ts +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env ts-node - -import * as fs from 'fs'; - -const filesToMigrate = [ - 'src/app/core/persistence/android-db-adapter.service.ts', - 'src/app/features/android/android-interface.ts', - 'src/app/features/android/store/android.effects.ts', -]; - -const CORE_LOG_IMPORT_RE = /from\s*['"][^'"]*core\/log['"]/; - -const migrateFile = (filePath: string): void => { - console.log(`Processing ${filePath}...`); - - let content = fs.readFileSync(filePath, 'utf8'); - let modified = false; - - // Replace Log.* method calls with DroidLog.* - const logPattern = /\bLog\.(log|err|error|info|warn|debug|verbose|critical)\b/g; - if (logPattern.test(content)) { - content = content.replace(logPattern, 'DroidLog.$1'); - modified = true; - } - - // Update imports - if (modified) { - // Check if file already imports from log - if (CORE_LOG_IMPORT_RE.test(content)) { - // Replace Log import with DroidLog - content = content.replace( - /import\s*{\s*([^}]*)\bLog\b([^}]*)\}\s*from\s*['"][^'"]*core\/log['"]/g, - (match, before, after) => { - const imports = (before + after) - .split(',') - .map((s) => s.trim()) - .filter((s) => s && s !== 'Log'); - imports.push('DroidLog'); - return `import { ${imports.join(', ')} } from '${match.includes('"') ? match.split('"')[1] : match.split("'")[1]}'`; - }, - ); - } else { - console.log(`Warning: Could not find log import in ${filePath}`); - } - } - - if (modified) { - fs.writeFileSync(filePath, content); - console.log(`✓ Migrated ${filePath}`); - } else { - console.log(`- No changes needed in ${filePath}`); - } -}; - -// Process all files -filesToMigrate.forEach(migrateFile); - -console.log('\nMigration complete!'); diff --git a/scripts/migrate-to-issue-log.ts b/scripts/migrate-to-issue-log.ts deleted file mode 100755 index bd60a16c53..0000000000 --- a/scripts/migrate-to-issue-log.ts +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env ts-node - -import { runLogMigration } from './log-migration-helper'; - -runLogMigration({ - description: 'Migrating Log to IssueLog in features/issue directory...', - fileLabel: 'TypeScript files in features/issue directory', - globPattern: 'src/app/features/issue/**/*.ts', - targetLogName: 'IssueLog', -}); diff --git a/scripts/migrate-to-plugin-log.ts b/scripts/migrate-to-plugin-log.ts deleted file mode 100755 index bd9e90bd9b..0000000000 --- a/scripts/migrate-to-plugin-log.ts +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env ts-node - -import { runLogMigration } from './log-migration-helper'; - -runLogMigration({ - description: 'Migrating Log to PluginLog in plugins directory...', - fileLabel: 'TypeScript files in plugins directory', - globPattern: 'src/app/plugins/**/*.ts', - targetLogName: 'PluginLog', -}); diff --git a/scripts/migrate-to-task-log.ts b/scripts/migrate-to-task-log.ts deleted file mode 100755 index 42906ac2e1..0000000000 --- a/scripts/migrate-to-task-log.ts +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env ts-node - -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; - -const taskFiles = glob.sync('src/app/features/tasks/**/*.ts', { - ignore: ['**/*.spec.ts', '**/node_modules/**'], -}); - -console.log(`Found ${taskFiles.length} task files to check`); - -let totalChanges = 0; - -function getRelativeImportPath(fromFile: string, toFile: string): string { - const fromDir = path.dirname(fromFile); - let relativePath = path.relative(fromDir, toFile).replace(/\\/g, '/'); - if (!relativePath.startsWith('.')) { - relativePath = './' + relativePath; - } - return relativePath.replace(/\.ts$/, ''); -} - -function migrateFile(filePath: string): void { - let content = fs.readFileSync(filePath, 'utf8'); - let modified = false; - let localChanges = 0; - - // Skip if file already uses TaskLog - if (content.includes('TaskLog')) { - return; - } - - // Replace console.* calls - const consolePatterns = [ - { pattern: /\bconsole\.log\(/g, replacement: 'TaskLog.log(' }, - { pattern: /\bconsole\.error\(/g, replacement: 'TaskLog.err(' }, - { pattern: /\bconsole\.info\(/g, replacement: 'TaskLog.info(' }, - { pattern: /\bconsole\.warn\(/g, replacement: 'TaskLog.warn(' }, - { pattern: /\bconsole\.debug\(/g, replacement: 'TaskLog.debug(' }, - ]; - - for (const { pattern, replacement } of consolePatterns) { - const matches = content.match(pattern); - if (matches) { - content = content.replace(pattern, replacement); - modified = true; - localChanges += matches.length; - } - } - - // Replace Log.* method calls with TaskLog.* - const logPattern = /\bLog\.(log|err|error|info|warn|debug|verbose|critical)\b/g; - const logMatches = content.match(logPattern); - if (logMatches) { - content = content.replace(logPattern, 'TaskLog.$1'); - modified = true; - localChanges += logMatches.length; - } - - // Update imports - if (modified) { - const logPath = getRelativeImportPath(filePath, 'src/app/core/log.ts'); - - // Check if file already imports from log - const importRegex = new RegExp( - `import\\s*{([^}]*)}\\s*from\\s*['"]${logPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}['"]`, - ); - const existingImport = content.match(importRegex); - - if (existingImport) { - // Update existing import - const imports = existingImport[1] - .split(',') - .map((s) => s.trim()) - .filter((s) => s && s !== 'Log'); - if (!imports.includes('TaskLog')) { - imports.push('TaskLog'); - } - content = content.replace( - importRegex, - `import { ${imports.join(', ')} } from '${logPath}'`, - ); - } else { - // Check for any Log import - const anyLogImport = content.match( - /import\s*{\s*([^}]*)\bLog\b([^}]*)\}\s*from\s*['"][^'"]*core\/log['"]/, - ); - if (anyLogImport) { - // Replace with TaskLog - content = content.replace( - /import\s*{\s*([^}]*)\bLog\b([^}]*)\}\s*from\s*['"][^'"]*core\/log['"]/g, - (match, before, after) => { - const imports = (before + after) - .split(',') - .map((s) => s.trim()) - .filter((s) => s && s !== 'Log'); - imports.push('TaskLog'); - const importPath = match.includes('"') - ? match.split('"')[1] - : match.split("'")[1]; - return `import { ${imports.join(', ')} } from '${importPath}'`; - }, - ); - } else if (!content.includes('TaskLog')) { - // Add new import at the top - const importStatement = `import { TaskLog } from '${logPath}';\n`; - - // Find the right place to insert the import - const firstImportMatch = content.match(/^import\s+/m); - if (firstImportMatch) { - const position = firstImportMatch.index!; - content = - content.slice(0, position) + importStatement + content.slice(position); - } else { - // If no imports, add after any leading comments - const afterComments = content.match(/^(\/\*[\s\S]*?\*\/|\/\/.*$)*/m); - if (afterComments) { - const position = afterComments[0].length; - content = - content.slice(0, position) + - (position > 0 ? '\n' : '') + - importStatement + - content.slice(position); - } else { - content = importStatement + content; - } - } - } - } - } - - if (modified) { - fs.writeFileSync(filePath, content); - console.log(`✓ ${filePath} (${localChanges} changes)`); - totalChanges += localChanges; - } -} - -// Process all files -taskFiles.forEach(migrateFile); - -console.log(`\nMigration complete! Total changes: ${totalChanges}`); diff --git a/scripts/remove-unused-log-imports.ts b/scripts/remove-unused-log-imports.ts deleted file mode 100644 index 348065ee71..0000000000 --- a/scripts/remove-unused-log-imports.ts +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env ts-node - -import * as fs from 'fs'; -import * as path from 'path'; - -const filesToFix = [ - 'src/app/core-ui/drop-list/drop-list.service.ts', - 'src/app/core-ui/side-nav/side-nav.component.ts', - 'src/app/core/banner/banner.service.ts', - 'src/app/features/config/form-cfgs/domina-mode-form.const.ts', - 'src/app/features/focus-mode/focus-mode.service.ts', - 'src/app/features/schedule/create-task-placeholder/create-task-placeholder.component.ts', - 'src/app/features/schedule/map-schedule-data/create-blocked-blocks-by-day-map.ts', - 'src/app/features/schedule/map-schedule-data/create-view-entries-for-day.ts', - 'src/app/features/schedule/map-schedule-data/insert-blocked-blocks-view-entries-for-schedule.ts', - 'src/app/features/schedule/map-schedule-data/map-to-schedule-days.ts', - 'src/app/features/task-repeat-cfg/sort-repeatable-task-cfg.ts', - 'src/app/features/work-context/store/work-context-meta.helper.ts', - 'src/app/root-store/index.ts', - 'src/app/ui/duration/input-duration-formly/input-duration-formly.component.ts', - 'src/app/ui/inline-markdown/inline-markdown.component.ts', - 'src/app/util/is-touch-only.ts', -]; - -function removeUnusedLogImport(filePath: string): void { - try { - const fullPath = path.join(process.cwd(), filePath); - let content = fs.readFileSync(fullPath, 'utf8'); - - // Check if Log is actually used in the file (excluding import statement and comments) - const importRegex = /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"][^'"]+['"]/g; - let contentWithoutImports = content.replace(importRegex, ''); - - // Remove single line comments - contentWithoutImports = contentWithoutImports.replace(/\/\/.*$/gm, ''); - // Remove multi-line comments - contentWithoutImports = contentWithoutImports.replace(/\/\*[\s\S]*?\*\//g, ''); - - const isLogUsed = /\bLog\./g.test(contentWithoutImports); - - if (!isLogUsed) { - // Remove Log from imports - content = content.replace( - /import\s+{([^}]*)\bLog\b([^}]*)}\s+from\s+(['"][^'"]+['"])/g, - (match, before, after, path) => { - // Clean up the remaining imports - const remainingImports = (before + after) - .split(',') - .map((s) => s.trim()) - .filter((s) => s && s !== 'Log') - .join(', '); - - if (remainingImports) { - return `import { ${remainingImports} } from ${path}`; - } else { - // If Log was the only import, remove the entire import line - return ''; - } - }, - ); - - // Clean up any empty lines left by removed imports - content = content.replace(/^\s*;\s*$/gm, ''); // Remove standalone semicolons - content = content.replace(/\n\n+/g, '\n\n'); // Replace multiple newlines with double newline - - fs.writeFileSync(fullPath, content, 'utf8'); - console.log(`Fixed: ${filePath}`); - } else { - console.log(`Skipped (Log is used): ${filePath}`); - } - } catch (error) { - console.error(`Error processing ${filePath}:`, error); - } -} - -console.log('Removing unused Log imports...\n'); - -filesToFix.forEach(removeUnusedLogImport); - -console.log('\nDone!');