Skip to content

Commit

Permalink
feat: skip reinstalling already installed plugin (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
auvred authored Aug 17, 2023
1 parent 51d2bd3 commit b6ed918
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 58 deletions.
52 changes: 0 additions & 52 deletions src/install-npm-packages.ts

This file was deleted.

137 changes: 137 additions & 0 deletions src/install-plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { spawn } from 'node:child_process'
import fs from 'node:fs'

import { PLUGINS_PACKAGE_JSON_PATH, PLUGIN_STORE_PATH } from './paths.js'
import { splitPluginNameAndVersion } from './utils.js'

const npmExecutable = process.platform.startsWith('win') ? 'npm.cmd' : 'npm'

function listStoreDependencies(): [string, string][] {
try {
const packageJson = JSON.parse(
fs.readFileSync(PLUGINS_PACKAGE_JSON_PATH, 'utf-8'),
) as unknown

if (
typeof packageJson === 'object' &&
packageJson &&
'dependencies' in packageJson &&
typeof packageJson.dependencies === 'object' &&
packageJson.dependencies
) {
return Object.entries(packageJson.dependencies)
}

return []
} catch {
return []
}
}

function filterPluginsToInstall(pluginNames: string[]) {
const storeDependencies = listStoreDependencies()
const pluginsToInstall: string[] = []
const installedPlugins: string[] = []

pluginNames.forEach(rawPluginName => {
let { name: pluginName, version: pluginVersion } =
splitPluginNameAndVersion(rawPluginName)
if (
pluginVersion &&
(pluginVersion.startsWith('^') || pluginVersion.startsWith('~'))
) {
pluginVersion = pluginVersion.slice(1)
}

const isPluginInstalled = storeDependencies.some(
([dependencyName, dependencyVersion]) => {
if (dependencyName !== pluginName) {
return false
}

if (!pluginVersion) {
return true
}

if (
dependencyVersion.startsWith('^') ||
dependencyVersion.startsWith('~')
) {
dependencyVersion = dependencyVersion.slice(1)
}

return dependencyVersion.startsWith(pluginVersion)
},
)

if (isPluginInstalled) {
installedPlugins.push(pluginName)
} else {
pluginsToInstall.push(rawPluginName)
}
})

return {
pluginsToInstall,
installedPlugins,
}
}

export async function installPlugins(pluginNames: string[]) {
if (!pluginNames.length) {
return
}

if (!fs.existsSync(PLUGIN_STORE_PATH)) {
fs.mkdirSync(PLUGIN_STORE_PATH)
}

if (!fs.existsSync(PLUGINS_PACKAGE_JSON_PATH)) {
fs.writeFileSync(PLUGINS_PACKAGE_JSON_PATH, '{}', { encoding: 'utf-8' })
}

const { pluginsToInstall, installedPlugins } =
filterPluginsToInstall(pluginNames)

if (installedPlugins.length) {
console.log('\n----- Already installed ----\n')
installedPlugins.forEach(pluginName => console.log(` - ${pluginName}`))
}

if (pluginsToInstall.length) {
console.log('\n---- Installing plugins ----\n')
pluginsToInstall.forEach(pluginName => console.log(` - ${pluginName}`))

const child = spawn(
npmExecutable,
[
'install',
'--ignore-scripts',
'--no-package-lock',
'--no-lockfile',
'--omit=dev',
'--install-strategy=shallow',
'--no-bin-links',
'--no-global',
...pluginsToInstall,
],
{
cwd: PLUGIN_STORE_PATH,
env: Object.assign({}, process.env, { NODE_ENV: 'production' }),
stdio: 'inherit',
},
)

return await new Promise<void>((resolve, reject) => {
child.on('error', err => {
reject(err)
})
child.on('exit', code => {
if (code === 0) {
return resolve()
}
reject()
})
})
}
}
9 changes: 4 additions & 5 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { resolve } from 'import-meta-resolve'

import { installNpmPackages } from './install-npm-packages.js'
import { installPlugins } from './install-plugins.js'
import { parseArgs } from './parse-args.js'
import { PLUGINS_PACKAGE_JSON_PATH } from './paths.js'
import { splitPluginNameAndVersion } from './utils.js'

export async function run(args: string[]) {
const { prettierArgs, pluginNames } = parseArgs(args)

if (pluginNames.length) {
try {
console.log('\n---- Installing plugins ----\n')
pluginNames.forEach(pluginName => console.log(' - ' + pluginName))
await installNpmPackages(pluginNames)
await installPlugins(pluginNames)
console.log('\n----- Running prettier -----\n')
} catch {
process.exit(1)
Expand All @@ -22,7 +21,7 @@ export async function run(args: string[]) {

const pnpPlugins: string[] = []
pluginNames.forEach(pluginName => {
pluginName = pluginName.split('@')[0]
pluginName = splitPluginNameAndVersion(pluginName).name
const resolved = resolve(pluginName, PLUGINS_PACKAGE_JSON_PATH.href)
pnpPlugins.push('--plugin', resolved)
})
Expand Down
6 changes: 5 additions & 1 deletion src/parse-args.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { splitPluginNameAndVersion } from './utils.js'

function extendPluginName(shortName: string) {
return 'prettier-plugin-' + shortName
}
Expand All @@ -11,7 +13,9 @@ export function parseArgs(args: string[]): {

function pushPluginName(pluginName: string) {
const isDuplicated = pluginNames.some(
name => name.split('@')[0] === pluginName.split('@')[0],
name =>
splitPluginNameAndVersion(name).name ===
splitPluginNameAndVersion(pluginName).name,
)

if (isDuplicated) {
Expand Down
19 changes: 19 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function splitPluginNameAndVersion(packageName: string): {
name: string
version: string | undefined
} {
let name = ''

if (packageName.startsWith('@')) {
name = '@'
packageName = packageName.slice(1)
}

name += packageName.split('@')[0]
const version = packageName.split('@')[1]

return {
name,
version,
}
}
54 changes: 54 additions & 0 deletions tests/integration/__tests__/__snapshots__/cli.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,60 @@ exports[`prettier-pnp cli > should install plugins with specific version 2`] = `
"
`;

exports[`prettier-pnp cli > should not try to install already installed plugins (with fixed version) 2`] = `
"
----- Already installed ----
- prettier-plugin-curly
----- Running prettier -----
/** --- FIXTURE --- */
const a = 5;
if (false) {
true;
}
"
`;

exports[`prettier-pnp cli > should not try to install already installed plugins (with fixed version) 3`] = `
"
----- Already installed ----
- prettier-plugin-curly
----- Running prettier -----
/** --- FIXTURE --- */
const a = 5;
if (false) {
true;
}
"
`;

exports[`prettier-pnp cli > should not try to install already installed plugins (with fixed version) 4`] = `
"
----- Already installed ----
- prettier-plugin-curly
----- Running prettier -----
/** --- FIXTURE --- */
const a = 5;
if (false) {
true;
}
"
`;

exports[`prettier-pnp cli > should pass rest args to prettier 1`] = `
"/** --- FIXTURE --- */
Expand Down
Loading

0 comments on commit b6ed918

Please sign in to comment.