Skip to content

Commit

Permalink
support pnpm
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolai Katkov committed Dec 16, 2023
1 parent 4afc440 commit 561c0db
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ For busy developers who appreciate the benefits of code linting but find it tedi
- No configuration needed
- Still fully flexible: you can specify your file patterns, disable rules that are not worth fixing , and have completely own, team- or company-wide ruleset (see [configuration](#configuration) section)
- Supports new projects and existing codebases
- Automatically updates linting dependencies using your project's dependency manager, Yarn or NPM
- Automatically updates linting dependencies using your project's dependency manager. Currently supports `npm`, `yarn` and `pnpm`.
- Supports monorepos - configures IDE once for the whole repo while keeping linting configurations per project

## Usage
Expand Down
70 changes: 63 additions & 7 deletions src/lib/context/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import type { LockFileObject } from '@yarnpkg/lockfile'
import { parse as parseYarnLock } from '@yarnpkg/lockfile'
import fs from 'fs'
import yaml from 'js-yaml'
import path from 'path'
import type { PackageJson } from 'type-fest'

import type { PackageLock } from '../../types/packageLock'
import type { PnpmLock } from '../../types/pnpmLock'
import { fileExists } from '../../util/file'

export type DependencyManager = 'npm' | 'yarn'
export type DependencyManager = 'npm' | 'yarn' | 'pnpm'

export interface InstalledPackage {
name: string
Expand Down Expand Up @@ -97,23 +99,77 @@ interface GetInstalledPackagesParameters {
projectDirectory: string
}

// eslint-disable-next-line sonarjs/cognitive-complexity
const getPnpmPackages = (projectDirectory: string): InstalledPackage[] => {
const installedPackages: InstalledPackage[] = []
const pnpmLockRaw = fs.readFileSync(path.join(projectDirectory, 'pnpm-lock.yaml'), 'utf8')
const pnpmLock = yaml.load(pnpmLockRaw) as PnpmLock

for (const workspace in pnpmLock.importers) {
if (Object.prototype.hasOwnProperty.call(pnpmLock.importers, workspace)) {
for (const dependencyName in pnpmLock.importers[workspace].dependencies) {
if (
Object.prototype.hasOwnProperty.call(
pnpmLock.importers[workspace].dependencies,
dependencyName
)
) {
const dependency = pnpmLock.importers[workspace].dependencies[dependencyName]
installedPackages.push({
name: dependencyName,
isDev: false,
version: dependency.version,
})
}
}
for (const dependencyName in pnpmLock.importers[workspace].devDependencies) {
if (
Object.prototype.hasOwnProperty.call(
pnpmLock.importers[workspace].devDependencies,
dependencyName
)
) {
const dependency = pnpmLock.importers[workspace].devDependencies[dependencyName]
installedPackages.push({
name: dependencyName,
isDev: true,
version: dependency.version,
})
}
}
}
}

return installedPackages
}

export const getInstalledPackages = (
parameters: GetInstalledPackagesParameters
): InstalledPackage[] => {
const { packageJson, dependencyManager, projectDirectory } = parameters
let installedPackages: InstalledPackage[] = []
installedPackages =
dependencyManager === 'npm'
? getNpmPackages(projectDirectory)
: getYarnPackages(packageJson, projectDirectory)
return installedPackages
switch (dependencyManager) {
case 'npm': {
return getNpmPackages(projectDirectory)
}
case 'yarn': {
return getYarnPackages(packageJson, projectDirectory)
}
case 'pnpm': {
return getPnpmPackages(projectDirectory)
}
default: {
return []
}
}
}

export const getDependencyManager = (projectDirectory: string): DependencyManager | undefined => {
if (fileExists(path.join(projectDirectory, 'package-lock.json'))) {
return 'npm'
} else if (fileExists(path.join(projectDirectory, 'yarn.lock'))) {
return 'yarn'
} else if (fileExists(path.join(projectDirectory, 'pnpm-lock.yaml'))) {
return 'pnpm'
}
return undefined
}
Expand Down
83 changes: 61 additions & 22 deletions src/lib/eslint/installDependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,27 @@ const installYarnDependencies = (parameters: InstallDependenciesParameters): voi
}
}

const installPnpmDependencies = (parameters: InstallDependenciesParameters): void => {
const { dependenciesToUpdate, devDependenciesToUpdate, cwd, debug } = parameters
const dependencyList = dependenciesToUpdate
.map(([dependency, version]) => `${dependency}@${version}`)
.join(' ')
const developmentDependencyList = devDependenciesToUpdate
.map(([dependency, version]) => `${dependency}@${version}`)
.join(' ')

if (dependencyList) {
execSync(`pnpm add ${dependencyList} -w`, { cwd, stdio: debug ? 'inherit' : 'ignore' })
}

if (developmentDependencyList) {
execSync(`pnpm add -D ${developmentDependencyList} -w`, {
cwd,
stdio: debug ? 'inherit' : 'ignore',
})
}
}

interface Parameters {
dependencyManager?: DependencyManager
dependencies: ExactDependency[]
Expand Down Expand Up @@ -102,27 +123,45 @@ export const installDependencies = (parameters: Parameters) => {

log.debug(`dependencies to install or update: ${readableDependencyList}`)

if (!dependencyManager) {
execSync('npm init -y', { cwd, stdio: debug ? 'inherit' : 'ignore' })
installNpmDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})
} else if (dependencyManager === 'npm') {
installNpmDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})
} else {
installYarnDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})
switch (dependencyManager) {
case 'npm': {
installNpmDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})

break
}
case 'yarn': {
installYarnDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})

break
}
case 'pnpm': {
installPnpmDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})

break
}
default: {
execSync('npm init -y', { cwd, stdio: debug ? 'inherit' : 'ignore' })
installNpmDependencies({
dependenciesToUpdate,
devDependenciesToUpdate,
cwd,
debug,
})
}
}
}
39 changes: 39 additions & 0 deletions src/types/pnpmLock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { JsonObject } from 'type-fest'

export interface PnpmLock {
lockfileVersion: string
settingsautoInstallPeers: {
autoInstallPeers: boolean
excludeLinksFromLockfile: boolean
}
importers: Record<
string,
{
dependencies: Record<string, PackageDescriptor>
devDependencies: Record<string, PackageDescriptor>
}
>
packages: Record<
string,
{
resolution: {
integrity: string
}
engines?: Record<string, string>
transitivePeerDependencies?: string[]
dependencies?: Record<string, string>
peerDependencies?: Record<string, string>
peerDependenciesMeta?: Record<string, JsonObject>
cpu?: string[]
os?: string[]
hasBin?: boolean
requiresBuild?: boolean
dev: boolean
}
>
}

interface PackageDescriptor {
specifier: string
version: string
}

0 comments on commit 561c0db

Please sign in to comment.