/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ import path from 'path'; import fs from 'fs-extra'; import {getInstalledPluginDetails} from 'flipper-plugin-lib'; import {kebabCase} from 'lodash'; export default async function ( dir: string, options: { noDependencies?: boolean; noScripts?: boolean; } = {}, ): Promise { const {noDependencies, noScripts} = Object.assign( { noDependencies: false, noScripts: false, }, options, ); if (!(await fs.pathExists(dir))) { return `Directory not found: ${dir}`; } const packageJsonPath = path.join(dir, 'package.json'); if (!(await fs.pathExists(packageJsonPath))) { return `package.json not found: ${packageJsonPath}`; } console.log(`⚙️ Migrating Flipper plugin package in ${dir}`); const packageJsonString = (await fs.readFile(packageJsonPath)).toString(); const packageJson = JSON.parse(packageJsonString); const pluginDetails = await getInstalledPluginDetails(dir, packageJson); if (pluginDetails.specVersion === 2) { console.log( `✅ Plugin is already defined according to the latest specification version.`, ); return; } const name = pluginDetails.name.startsWith('flipper-plugin-') ? pluginDetails.name : `flipper-plugin-${kebabCase(pluginDetails.name)}`; const keys = Object.keys(packageJson); packageJson.name = name; packageJson.main = pluginDetails.main; if (!packageJson.flipperBundlerEntry) { const index = keys.indexOf('main'); keys.splice(index + 1, 0, 'flipperBundlerEntry'); } packageJson.flipperBundlerEntry = pluginDetails.source; if (!packageJson.id) { const index = keys.indexOf('name'); keys.splice(index + 1, 0, 'id'); } packageJson.id = pluginDetails.id; if (!packageJson.$schema) { keys.unshift('$schema'); } packageJson.$schema = 'https://fbflipper.com/schemas/plugin-package/v2.json'; if (!packageJson.keywords) { keys.push('keywords'); } if ( !packageJson.keywords || !packageJson.keywords.includes('flipper-plugin') ) { packageJson.keywords = ['flipper-plugin', ...(packageJson.keywords || [])]; } if (!noDependencies) { const dependenciesFieldIndex = keys.indexOf('dependencies'); if (packageJson.dependencies && packageJson.dependencies.flipper) { delete packageJson.dependencies.flipper; } if (!packageJson.peerDependencies) { if (dependenciesFieldIndex === -1) { keys.push('peerDependencies'); } else { if (Object.keys(packageJson.dependencies).length === 0) { // If no other dependencies except 'flipper' then we need to remove 'dependencies' and add 'peerDependencies' instead keys.splice(dependenciesFieldIndex, 1, 'peerDependencies'); } else { // If there are other dependencies except 'flipper', then keys.splice(dependenciesFieldIndex + 1, 0, 'peerDependencies'); } } } packageJson.peerDependencies = { ...packageJson.peerDependencies, flipper: 'latest', }; if (!packageJson.devDependencies) { const peerDependenciesFieldIndex = keys.indexOf('peerDependencies'); keys.splice(peerDependenciesFieldIndex + 1, 0, 'devDependencies'); } packageJson.devDependencies = { ...packageJson.devDependencies, flipper: 'latest', 'flipper-pkg': 'latest', }; } if (!noScripts) { if (!packageJson.scripts) { keys.push('scripts'); } packageJson.scripts = { ...packageJson.scripts, prepack: (packageJson.scripts?.prepack ? packageJson.scripts!.prepack! + ' && ' : '') + 'flipper-pkg lint && flipper-pkg bundle', }; } const newPackageJson = keys.reduce((result, key) => { result[key] = packageJson[key]; return result; }, {}); const newPackageJsonString = JSON.stringify(newPackageJson, undefined, 2); await fs.writeFile(packageJsonPath, newPackageJsonString); console.log(`✅ Plugin migrated to the latest specification version 2.`); }