-
Notifications
You must be signed in to change notification settings - Fork 620
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: update packages script [skip ci]
- Loading branch information
1 parent
c6f6401
commit c409f7c
Showing
18 changed files
with
531 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
const { updatePackages, presets, getUserInput } = require("./updatePackagesLib/index"); | ||
|
||
(async () => { | ||
const input = await getUserInput({ | ||
presets | ||
}); | ||
if (!input) { | ||
return; | ||
} | ||
|
||
return updatePackages(input); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import loadJsonFile from "load-json-file"; | ||
import { IBasicPackage, IPackageJson } from "./types"; | ||
import path from "path"; | ||
import fs from "fs"; | ||
import semver from "semver"; | ||
|
||
export interface IBasicPackageParams { | ||
packages: string[]; | ||
matching: RegExp; | ||
} | ||
|
||
interface IFindPackagesParams { | ||
collection: IBasicPackage[]; | ||
json: IPackageJson; | ||
matching: RegExp; | ||
} | ||
|
||
const types = ["dependencies", "devDependencies", "peerDependencies"] as const; | ||
|
||
export class BasicPackages { | ||
public readonly packages: IBasicPackage[]; | ||
|
||
private constructor(packages: IBasicPackage[]) { | ||
this.packages = packages; | ||
} | ||
|
||
public static async create(params: IBasicPackageParams): Promise<BasicPackages> { | ||
const { packages, matching } = params; | ||
const results = packages.reduce<IBasicPackage[]>((collection, pkg) => { | ||
const target = path.resolve(pkg, "package.json"); | ||
if (!fs.existsSync(target)) { | ||
console.log(`File not found: ${target}`); | ||
return collection; | ||
} | ||
const json = loadJsonFile.sync<IPackageJson>(target); | ||
return BasicPackages.findPackages({ | ||
collection, | ||
json, | ||
matching | ||
}); | ||
}, []); | ||
|
||
return new BasicPackages(results); | ||
} | ||
|
||
private static findPackages(params: IFindPackagesParams): IBasicPackage[] { | ||
const { collection, json, matching } = params; | ||
return types.reduce<IBasicPackage[]>((packages, type) => { | ||
const deps = json[type]; | ||
if (!deps) { | ||
return packages; | ||
} | ||
for (const name in deps) { | ||
if (name.match(matching) === null) { | ||
continue; | ||
} | ||
const existing = packages.find(p => p.name === name); | ||
if (!existing) { | ||
const version = semver.coerce(deps[name]); | ||
if (!version) { | ||
console.warn(`Could not coerce version "${deps[name]}" for ${name}`); | ||
continue; | ||
} | ||
packages.push({ | ||
name, | ||
version | ||
}); | ||
|
||
continue; | ||
} | ||
const version = semver.coerce(deps[name]); | ||
if (!version) { | ||
continue; | ||
} | ||
if (!semver.gt(existing.version, version)) { | ||
continue; | ||
} | ||
existing.version = version; | ||
} | ||
|
||
return packages; | ||
}, Array.from(collection)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import execa from "execa"; | ||
import semver from "semver"; | ||
import { IBasicPackage, IVersionedPackage } from "./types"; | ||
|
||
export interface IGetUpdatableParams { | ||
packages: IBasicPackage[]; | ||
} | ||
|
||
export class LatestVersionPackages { | ||
private readonly cache: WeakMap<IBasicPackage[], IVersionedPackage[]> = new WeakMap(); | ||
|
||
public async getUpdatable(params: IGetUpdatableParams): Promise<IVersionedPackage[]> { | ||
const cache = this.cache.get(params.packages); | ||
if (cache) { | ||
return cache; | ||
} | ||
|
||
const results: IVersionedPackage[] = []; | ||
|
||
for (const localPackage of params.packages) { | ||
try { | ||
const result = await execa("npm", ["show", localPackage.name, "version"]); | ||
if (!result.stdout) { | ||
console.log(`Could not find "${localPackage.name}" latest version on npm.`); | ||
continue; | ||
} | ||
const npmPackageVersion = semver.coerce(result.stdout); | ||
if (!npmPackageVersion) { | ||
console.log( | ||
`Could not coerce "${localPackage.name}" latest version "${result.stdout}" from npm.` | ||
); | ||
continue; | ||
} | ||
if (semver.gte(localPackage.version, npmPackageVersion)) { | ||
continue; | ||
} | ||
|
||
results.push({ | ||
...localPackage, | ||
version: localPackage.version, | ||
latestVersion: npmPackageVersion | ||
}); | ||
} catch (ex) { | ||
console.error(`Could not find "${localPackage}" latest version on npm.`, ex); | ||
} | ||
} | ||
|
||
this.cache.set(params.packages, results); | ||
return results; | ||
} | ||
|
||
public static async create() { | ||
return new LatestVersionPackages(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { IPackageJson, IVersionedPackage } from "./types"; | ||
import loadJsonFile from "load-json-file"; | ||
import writeJsonFile from "write-json-file"; | ||
import execa from "execa"; | ||
|
||
export interface IResolutionPackagesParams { | ||
packages: IVersionedPackage[]; | ||
path: string; | ||
skip: boolean; | ||
} | ||
|
||
export class ResolutionPackages { | ||
private readonly skip: boolean; | ||
private readonly packages: IVersionedPackage[]; | ||
private readonly path: string; | ||
private addedToResolutions: IVersionedPackage[] | undefined; | ||
|
||
private constructor(params: IResolutionPackagesParams) { | ||
this.skip = params.skip; | ||
this.path = params.path; | ||
this.packages = params.packages; | ||
} | ||
|
||
public static async create(params: IResolutionPackagesParams): Promise<ResolutionPackages> { | ||
return new ResolutionPackages(params); | ||
} | ||
|
||
public async addToPackageJson(): Promise<void> { | ||
if (this.skip) { | ||
return; | ||
} else if (this.addedToResolutions) { | ||
throw new Error(`Cannot execute addToPackageJson() twice.`); | ||
} | ||
this.addedToResolutions = []; | ||
const rootPackageJson = loadJsonFile.sync<IPackageJson>(this.path); | ||
for (const pkg of this.packages) { | ||
if (!rootPackageJson.resolutions[pkg.name]) { | ||
rootPackageJson.resolutions[pkg.name] = `^${pkg.latestVersion.raw}`; | ||
this.addedToResolutions.push(pkg); | ||
} | ||
if (!rootPackageJson.devDependencies) { | ||
rootPackageJson.devDependencies = {}; | ||
} | ||
if (rootPackageJson.devDependencies[pkg.name]) { | ||
continue; | ||
} | ||
rootPackageJson.devDependencies[pkg.name] = `^${pkg.latestVersion.raw}`; | ||
} | ||
writeJsonFile.sync(this.path, rootPackageJson); | ||
await execa("yarn"); | ||
} | ||
|
||
public async removeFromPackageJson(): Promise<void> { | ||
if (this.skip || !this.addedToResolutions?.length) { | ||
return; | ||
} | ||
const rootPackageJsonUp = loadJsonFile.sync<IPackageJson>(this.path); | ||
if (!rootPackageJsonUp.resolutions) { | ||
return; | ||
} | ||
for (const pkg of this.packages) { | ||
delete rootPackageJsonUp.resolutions[pkg.name]; | ||
} | ||
writeJsonFile.sync(this.path, rootPackageJsonUp); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { IVersionedPackage } from "./types"; | ||
import execa from "execa"; | ||
|
||
export interface IUpPackagesParams { | ||
packages: IVersionedPackage[]; | ||
} | ||
|
||
export class UpPackages { | ||
private readonly packages: IVersionedPackage[]; | ||
|
||
private constructor(params: IUpPackagesParams) { | ||
this.packages = params.packages; | ||
} | ||
|
||
public static async create(params: IUpPackagesParams): Promise<UpPackages> { | ||
return new UpPackages(params); | ||
} | ||
|
||
public async process(): Promise<void> { | ||
for (const pkg of this.packages) { | ||
await execa("yarn", ["up", `${pkg}@^${pkg.latestVersion.raw}`]); | ||
console.log(`${pkg}: ${pkg.version.raw} -> ${pkg.latestVersion.raw}`); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export interface IPreset { | ||
name: string; | ||
matching: RegExp; | ||
skipResolutions: boolean; | ||
} | ||
export interface ICreatePresetCb { | ||
(): IPreset; | ||
} | ||
|
||
export const createPreset = (cb: ICreatePresetCb) => { | ||
return cb(); | ||
}; |
Oops, something went wrong.