forked from jsnbuchanan/crowd-funder-for-time-pwa
Add comprehensive migration documentation and testing infrastructure
- Add TODO annotation to MembersList.vue requiring human testing validation - Create migration templates for systematic component migration - Add best practices guide for PlatformServiceMixin usage - Create ESLint rules template for pattern enforcement - Add validation script to track migration progress - Document Phase 1 completion summary with current state Migration Infrastructure: - Component migration checklist template - Automated validation script (validate-migration.sh) - Best practices documentation - ESLint rules for preventing regression Status: MembersList.vue migration complete but requires human testing Next: Select next component for migration when ready to continue
This commit is contained in:
307
docs/migration-templates/eslint-rules.md
Normal file
307
docs/migration-templates/eslint-rules.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# ESLint Rules for PlatformServiceMixin Migration
|
||||
|
||||
## Overview
|
||||
Custom ESLint rules to enforce PlatformServiceMixin patterns and prevent regression to legacy patterns.
|
||||
|
||||
## Rules Configuration
|
||||
|
||||
Add to `.eslintrc.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
// ... existing config
|
||||
rules: {
|
||||
// ... existing rules
|
||||
|
||||
// Custom rules for PlatformServiceMixin migration
|
||||
'timesafari/no-direct-database-util': 'error',
|
||||
'timesafari/no-legacy-logging': 'error',
|
||||
'timesafari/require-mixin-for-database': 'error',
|
||||
'timesafari/no-direct-platform-service': 'warn',
|
||||
'timesafari/prefer-mixin-methods': 'warn',
|
||||
},
|
||||
|
||||
// Custom rules plugin
|
||||
plugins: ['timesafari'],
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Rules Implementation
|
||||
|
||||
Create `eslint-plugin-timesafari/index.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-direct-database-util': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow direct imports from databaseUtil',
|
||||
category: 'Migration',
|
||||
recommended: true,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source.value.includes('databaseUtil')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Direct databaseUtil imports are deprecated. Use PlatformServiceMixin instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-legacy-logging': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow legacy logging methods',
|
||||
category: 'Migration',
|
||||
recommended: true,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.specifiers.some(spec => spec.imported?.name === 'logConsoleAndDb')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'logConsoleAndDb is deprecated. Use PlatformServiceMixin $log methods instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (node.callee.name === 'logConsoleAndDb') {
|
||||
context.report({
|
||||
node,
|
||||
message: 'logConsoleAndDb is deprecated. Use this.$logAndConsole() instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'require-mixin-for-database': {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Require PlatformServiceMixin for components using database operations',
|
||||
category: 'Migration',
|
||||
recommended: true,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
let hasDbOperations = false;
|
||||
let hasMixin = false;
|
||||
|
||||
return {
|
||||
CallExpression(node) {
|
||||
// Check for database operations
|
||||
if (node.callee.property &&
|
||||
['dbQuery', 'dbExec', 'dbGetOneRow'].includes(node.callee.property.name)) {
|
||||
hasDbOperations = true;
|
||||
}
|
||||
},
|
||||
Property(node) {
|
||||
// Check for mixin usage
|
||||
if (node.key.name === 'mixins' &&
|
||||
node.value.elements?.some(el => el.name === 'PlatformServiceMixin')) {
|
||||
hasMixin = true;
|
||||
}
|
||||
},
|
||||
'Program:exit'() {
|
||||
if (hasDbOperations && !hasMixin) {
|
||||
context.report({
|
||||
node: context.getSourceCode().ast,
|
||||
message: 'Components using database operations should include PlatformServiceMixin.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-direct-platform-service': {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Discourage direct PlatformServiceFactory usage',
|
||||
category: 'Migration',
|
||||
recommended: false,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (node.callee.object?.name === 'PlatformServiceFactory' &&
|
||||
node.callee.property?.name === 'getInstance') {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Consider using PlatformServiceMixin methods instead of direct PlatformServiceFactory.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'prefer-mixin-methods': {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Prefer mixin convenience methods over direct database calls',
|
||||
category: 'Migration',
|
||||
recommended: false,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
// Check for patterns that could use mixin methods
|
||||
if (node.callee.property?.name === 'dbQuery') {
|
||||
const arg = node.arguments[0];
|
||||
if (arg && arg.type === 'Literal') {
|
||||
const sql = arg.value.toLowerCase();
|
||||
if (sql.includes('select * from contacts')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Consider using this.$getAllContacts() instead of direct SQL.',
|
||||
});
|
||||
}
|
||||
if (sql.includes('select * from settings')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Consider using this.$settings() instead of direct SQL.',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Pre-commit Hook
|
||||
|
||||
Create `.pre-commit-config.yaml`:
|
||||
|
||||
```yaml
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: eslint-migration-check
|
||||
name: ESLint Migration Check
|
||||
entry: npx eslint --ext .vue --rule 'timesafari/no-direct-database-util: error'
|
||||
language: system
|
||||
files: \.vue$
|
||||
|
||||
- id: no-legacy-logging
|
||||
name: No Legacy Logging
|
||||
entry: bash -c 'if grep -r "logConsoleAndDb" src/ --include="*.vue" --include="*.ts"; then echo "Found legacy logging imports"; exit 1; fi'
|
||||
language: system
|
||||
pass_filenames: false
|
||||
```
|
||||
|
||||
## Migration Validation Script
|
||||
|
||||
Create `scripts/validate-migration.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "🔍 Validating PlatformServiceMixin migration..."
|
||||
|
||||
# Check for legacy patterns
|
||||
echo "Checking for legacy databaseUtil imports..."
|
||||
LEGACY_DB_IMPORTS=$(grep -r "import.*databaseUtil" src/ --include="*.vue" --include="*.ts" | wc -l)
|
||||
echo "Found $LEGACY_DB_IMPORTS legacy databaseUtil imports"
|
||||
|
||||
echo "Checking for legacy logging imports..."
|
||||
LEGACY_LOG_IMPORTS=$(grep -r "logConsoleAndDb" src/ --include="*.vue" --include="*.ts" | wc -l)
|
||||
echo "Found $LEGACY_LOG_IMPORTS legacy logging imports"
|
||||
|
||||
# Check for mixin usage
|
||||
echo "Checking for PlatformServiceMixin usage..."
|
||||
MIXIN_USAGE=$(grep -r "PlatformServiceMixin" src/ --include="*.vue" | wc -l)
|
||||
echo "Found $MIXIN_USAGE files using PlatformServiceMixin"
|
||||
|
||||
# Check for direct PlatformService usage
|
||||
echo "Checking for direct PlatformService usage..."
|
||||
DIRECT_PLATFORM=$(grep -r "PlatformServiceFactory.getInstance" src/ --include="*.vue" --include="*.ts" | wc -l)
|
||||
echo "Found $DIRECT_PLATFORM direct PlatformService usages"
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "📊 Migration Status Summary:"
|
||||
echo "- Legacy databaseUtil imports: $LEGACY_DB_IMPORTS (should be 0)"
|
||||
echo "- Legacy logging imports: $LEGACY_LOG_IMPORTS (should be 0)"
|
||||
echo "- Mixin usage: $MIXIN_USAGE (should be high)"
|
||||
echo "- Direct PlatformService usage: $DIRECT_PLATFORM (should be low)"
|
||||
|
||||
# Set exit code based on legacy usage
|
||||
if [ $LEGACY_DB_IMPORTS -gt 0 ] || [ $LEGACY_LOG_IMPORTS -gt 0 ]; then
|
||||
echo "❌ Migration validation failed - legacy patterns found"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Migration validation passed - no legacy patterns found"
|
||||
exit 0
|
||||
fi
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Install ESLint rules**:
|
||||
```bash
|
||||
npm install --save-dev eslint-plugin-timesafari
|
||||
```
|
||||
|
||||
2. **Run validation**:
|
||||
```bash
|
||||
npm run lint
|
||||
./scripts/validate-migration.sh
|
||||
```
|
||||
|
||||
3. **Fix issues automatically**:
|
||||
```bash
|
||||
npm run lint -- --fix
|
||||
```
|
||||
|
||||
## IDE Integration
|
||||
|
||||
### VS Code Settings
|
||||
|
||||
Add to `.vscode/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"vue"
|
||||
],
|
||||
"eslint.options": {
|
||||
"extensions": [".js", ".ts", ".vue"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### WebStorm Settings
|
||||
|
||||
1. Go to Settings → Languages & Frameworks → JavaScript → Code Quality Tools → ESLint
|
||||
2. Enable ESLint
|
||||
3. Set configuration file to `.eslintrc.js`
|
||||
4. Add `.vue` to file extensions
|
||||
Reference in New Issue
Block a user