Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions eslint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const ionic = require('@ionic/eslint-config/recommended');

module.exports = [
{
ignores: [
'**/dist/**',
// lint TypeScript only
'**/*.js',
'**/*.mjs',
'**/*.cjs',
],
},
...ionic,
];
12 changes: 5 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"lint": "npm run eslint && npm run prettier -- --check",
"fmt": "npm run eslint -- --fix && npm run prettier -- --write",
"eslint": "eslint . --ext ts",
"eslint": "eslint .",
"prettier": "prettier \"**/*.{css,html,js,mjs,ts,json}\"",
"build": "npm run clean && tsc",
"clean": "rimraf ./dist",
Expand All @@ -30,19 +30,17 @@
"author": "Ionic Team <hi@ionicframework.com>",
"license": "MIT",
"prettier": "@ionic/prettier-config",
"eslintConfig": {
"extends": "@ionic/eslint-config/recommended"
},
"bugs": {
"url": "https://github.com/ionic-team/migrate-capacitor-plugin/issues"
},
"homepage": "https://github.com/ionic-team/migrate-capacitor-plugin#readme",
"devDependencies": {
"@ionic/eslint-config": "^0.4.0",
"@ionic/eslint-config": "^0.5.0",
"@ionic/prettier-config": "^4.0.0",
"@types/fs-extra": "^11.0.4",
"@types/node": "^24.10.1",
"eslint": "^8.57.0",
"@types/semver": "^7.7.1",
"eslint": "^10.0.0",
"prettier": "^3.6.2",
"typescript": "^5.9.3"
},
Expand All @@ -54,4 +52,4 @@
"rimraf": "^6.1.0",
"semver": "^7.7.3"
}
}
}
76 changes: 73 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,52 @@ const gradleVersion = '9.5.1';
const AGPVersion = '9.2.1';
const gmsVersion = '4.5.0';
const docgenVersion = '^0.3.1';
const eslintVersion = '^8.57.1';
const ionicEslintVersion = '^0.4.0';
const eslintVersion = '^10.0.0';
const ionicEslintVersion = '^0.5.0';
const ionicPrettierVersion = '^4.0.0';

// Flat config has no equivalent of .eslintignore, so its entries move into the config.
// Keep them: a plugin that excluded docs/ or website/ should not start linting them.
function eslintIgnoresFrom(eslintIgnorePath: string): string[] {
const entries = existsSync(eslintIgnorePath)
? readFileSync(eslintIgnorePath, 'utf-8')
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length > 0 && !line.startsWith('#'))
: ['build', 'dist', 'example-app'];

return entries.map((entry) => {
if (entry.endsWith('/**')) {
return entry;
}
const bare = entry.replace(/\/$/, '');
const name = bare.split('/').pop() ?? bare;
// a dot anywhere but the front means it is a file, not a directory
if (name.indexOf('.') > 0) {
return bare;
}
return bare.includes('/') ? `${bare}/**` : `**/${bare}/**`;
});
}

function eslintConfigCjsFor(ignores: string[]): string {
const lines = ignores.map((entry) => ` '${entry}',`).join('\n');
return `const ionic = require('@ionic/eslint-config/recommended');

module.exports = [
{
ignores: [
${lines}
// the old lint script passed --ext ts, which flat config ignores
'**/*.js',
'**/*.mjs',
'**/*.cjs',
],
},
...ionic,
];
`;
}
const ionicSwiftlintVersion = '^2.0.0';
const prettierJavaVersion = '^2.7.7';
const prettierVersion = '^3.6.2';
Expand Down Expand Up @@ -82,11 +125,17 @@ export const run = async (): Promise<void> => {
pluginJSON.peerDependencies[dep] = `>=${coreVersion}`;
}
}
let eslintUpdated = false;
if (pluginJSON.devDependencies?.['@ionic/eslint-config']) {
pluginJSON.devDependencies['@ionic/eslint-config'] = ionicEslintVersion;
if (pluginJSON.devDependencies?.['eslint']) {
pluginJSON.devDependencies['eslint'] = eslintVersion;
}
delete pluginJSON.eslintConfig;
if (pluginJSON.scripts?.['eslint']) {
pluginJSON.scripts['eslint'] = pluginJSON.scripts['eslint'].replace(' --ext ts', '');
}
eslintUpdated = true;
}
if (pluginJSON.devDependencies?.['@ionic/swiftlint-config']) {
pluginJSON.devDependencies['@ionic/swiftlint-config'] = ionicSwiftlintVersion;
Expand Down Expand Up @@ -165,6 +214,20 @@ export const run = async (): Promise<void> => {

writeFileSync(packageJson, packageJsonText, 'utf-8');

if (eslintUpdated) {
const ignores = eslintIgnoresFrom(join(dir, '.eslintignore'));
// ESLint 10 reads neither of these, so leaving them behind is just dead config
const stale = ['.eslintignore', '.eslintrc', '.eslintrc.js', '.eslintrc.cjs', '.eslintrc.json', '.eslintrc.yml'];
for (const file of stale.map((name) => join(dir, name))) {
if (existsSync(file)) {
removeSync(file);
}
}
if (!['eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs'].some((file) => existsSync(join(dir, file)))) {
writeFileSync(join(dir, 'eslint.config.cjs'), eslintConfigCjsFor(ignores), 'utf-8');
}
}

rimraf.sync(join(dir, 'node_modules/@capacitor'));
rimraf.sync(join(dir, 'package-lock.json'));

Expand All @@ -173,7 +236,7 @@ export const run = async (): Promise<void> => {
...opts,
cwd: dir,
});
} catch (e: any) {
} catch {
logger.warn('npm install failed, please, install the dependencies using your package manager of choice');
}

Expand Down Expand Up @@ -238,6 +301,13 @@ export const run = async (): Promise<void> => {

logger.info('Plugin migrated to Capacitor 9!');

if (eslintUpdated) {
logger.info('');
logger.info('⚠️ Note: ESLint has been updated to v10 and @ionic/eslint-config to v1, which uses flat config.');
logger.info('An eslint.config.cjs file was added; .eslintignore and the eslintConfig block in package.json were removed.');
logger.info('Running lint may surface new reports; see https://github.com/ionic-team/eslint-config#migrating-from-04-or-earlier');
}

if (prettierUpdatedFromV2) {
logger.info('');
logger.info('⚠️ Note: Prettier has been updated from v2 to v3.');
Expand Down