mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
* chore(scripts): remove one-off codemod scripts [#8260 - Tier A] * Address PR feedback
This commit is contained in:
parent
c6480d1cae
commit
6f1cacc553
11 changed files with 10 additions and 999 deletions
|
|
@ -227,13 +227,13 @@ privateCfg: {
|
||||||
|
|
||||||
## Security Properties
|
## Security Properties
|
||||||
|
|
||||||
| Property | Guarantee |
|
| Property | Guarantee |
|
||||||
| ------------------- | ---------------------------------------------- |
|
| ------------------- | ----------------------------------------------- |
|
||||||
| **Confidentiality** | Server cannot read operation payloads |
|
| **Confidentiality** | Server cannot read operation payloads |
|
||||||
| **Integrity** | GCM auth tag detects tampering of the _payload_ |
|
| **Integrity** | GCM auth tag detects tampering of the _payload_ |
|
||||||
| **Key Security** | Argon2id makes brute-force expensive |
|
| **Key Security** | Argon2id makes brute-force expensive |
|
||||||
| **Forward Secrecy** | Each operation uses random IV |
|
| **Forward Secrecy** | Each operation uses random IV |
|
||||||
| **Wrong Password** | Decryption fails, operation rejected |
|
| **Wrong Password** | Decryption fails, operation rejected |
|
||||||
|
|
||||||
> **Integrity scope (important).** Only `op.payload` is encrypted and covered by
|
> **Integrity scope (important).** Only `op.payload` is encrypted and covered by
|
||||||
> the AES-GCM authentication tag. Every other operation field — `actionType`,
|
> the AES-GCM authentication tag. Every other operation field — `actionType`,
|
||||||
|
|
@ -245,7 +245,7 @@ privateCfg: {
|
||||||
> tamper vectors:
|
> tamper vectors:
|
||||||
>
|
>
|
||||||
> - **Plaintext-injection downgrade:** a forged op with `isPayloadEncrypted=false`
|
> - **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`
|
> op forgery on an encryption-mandatory client. `assertOpsEncryptedWhenExpected`
|
||||||
> rejects any inbound plaintext op (download + piggyback) when encryption is
|
> rejects any inbound plaintext op (download + piggyback) when encryption is
|
||||||
> **enabled in config** (`isEncryptionMandatory && isEncryptionEnabled()` —
|
> **enabled in config** (`isEncryptionMandatory && isEncryptionEnabled()` —
|
||||||
|
|
@ -254,8 +254,8 @@ privateCfg: {
|
||||||
> re-uploads all data encrypted, so no legitimate plaintext op remains — this
|
> re-uploads all data encrypted, so no legitimate plaintext op remains — this
|
||||||
> rests on the server contract that `deleteAllData()` removes every downloadable
|
> 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
|
> plaintext op. This is the SuperSync op-level twin of the file-based GHSA-vrc7
|
||||||
> download guard and the GHSA-9544 *upload* guard.
|
> download guard and the GHSA-9544 _upload_ guard.
|
||||||
> - **LWW `entityId` retarget:** the client rejects an *encrypted* LWW-update op
|
> - **LWW `entityId` retarget:** the client rejects an _encrypted_ LWW-update op
|
||||||
> whose authenticated `payload.id` does not equal `op.entityId`
|
> whose authenticated `payload.id` does not equal `op.entityId`
|
||||||
> (`verify-decrypted-op-integrity.ts`).
|
> (`verify-decrypted-op-integrity.ts`).
|
||||||
>
|
>
|
||||||
|
|
@ -270,7 +270,7 @@ privateCfg: {
|
||||||
> authenticate it.
|
> authenticate it.
|
||||||
>
|
>
|
||||||
> Known limitation: a peer running an app version that predates the GHSA-9544
|
> 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.
|
> here with the tamper message. Recovery is to update the old peer.
|
||||||
>
|
>
|
||||||
> Full protection — binding the metadata (and the encryption flag) as GCM AAD
|
> Full protection — binding the metadata (and the encryption flag) as GCM AAD
|
||||||
|
|
|
||||||
|
|
@ -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<string>();
|
|
||||||
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<string>();
|
|
||||||
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();
|
|
||||||
|
|
@ -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'),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
@ -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.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -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();
|
|
||||||
|
|
@ -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();
|
|
||||||
|
|
@ -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!');
|
|
||||||
|
|
@ -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',
|
|
||||||
});
|
|
||||||
|
|
@ -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',
|
|
||||||
});
|
|
||||||
|
|
@ -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}`);
|
|
||||||
|
|
@ -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!');
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue