diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f5b41d..f4d5c97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,4 +22,4 @@ jobs: - name: Build and run tests for pnpm-sync-lib run: pnpm --filter pnpm-sync-lib run build && pnpm --filter pnpm-sync-lib run test - name: Build and run tests for pnpm-sync - run: pnpm --filter pnpm-sync run build && pnpm --filter pnpm-sync run test + run: pnpm --filter pnpm-sync run build && pnpm --filter pnpm-sync run test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c4fb4d2..383aa8c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -27,4 +27,4 @@ jobs: run: | npm config set "//registry.npmjs.org/:_authToken" "${NPM_AUTH_TOKEN}" pnpm --filter pnpm-sync-lib publish --no-git-checks - pnpm --filter pnpm-sync publish --no-git-checks \ No newline at end of file + pnpm --filter pnpm-sync publish --no-git-checks diff --git a/packages/pnpm-sync-lib/.eslintrc.js b/packages/pnpm-sync-lib/.eslintrc.js index 246aa14..e11197c 100644 --- a/packages/pnpm-sync-lib/.eslintrc.js +++ b/packages/pnpm-sync-lib/.eslintrc.js @@ -1,5 +1,5 @@ -require("@rushstack/eslint-patch/modern-module-resolution"); +require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: ['@rushstack/eslint-config/profile/node'], parserOptions: { tsconfigRootDir: __dirname } -}; \ No newline at end of file +}; diff --git a/packages/pnpm-sync-lib/src/index.ts b/packages/pnpm-sync-lib/src/index.ts index 0143dee..2c362d7 100644 --- a/packages/pnpm-sync-lib/src/index.ts +++ b/packages/pnpm-sync-lib/src/index.ts @@ -5,14 +5,6 @@ * @packageDocumentation */ -export { pnpmSyncCopyAsync, type IPnpmSyncCopyOptions } from "./pnpmSyncCopy"; -export { - pnpmSyncPrepareAsync, - type IPnpmSyncPrepareOptions, -} from "./pnpmSyncPrepare"; -export type { - ILockfile, - ILockfileImporter, - IVersionSpecifier, - IDependencyMeta, -} from "./interfaces"; +export { pnpmSyncCopyAsync, type IPnpmSyncCopyOptions } from './pnpmSyncCopy'; +export { pnpmSyncPrepareAsync, type IPnpmSyncPrepareOptions } from './pnpmSyncPrepare'; +export type { ILockfile, ILockfileImporter, IVersionSpecifier, IDependencyMeta } from './interfaces'; diff --git a/packages/pnpm-sync-lib/src/pnpmSyncCopy.ts b/packages/pnpm-sync-lib/src/pnpmSyncCopy.ts index 9641ce9..48bf7fb 100644 --- a/packages/pnpm-sync-lib/src/pnpmSyncCopy.ts +++ b/packages/pnpm-sync-lib/src/pnpmSyncCopy.ts @@ -1,5 +1,5 @@ -import path from "path"; -import fs from "fs"; +import path from 'path'; +import fs from 'fs'; /** * @beta @@ -29,26 +29,24 @@ export interface IPnpmSyncCopyOptions { * @beta */ export async function pnpmSyncCopyAsync({ - pnpmSyncJsonPath = "", + pnpmSyncJsonPath = '', getPackageIncludedFiles, forEachAsyncWithConcurrency, - ensureFolder, + ensureFolder }: IPnpmSyncCopyOptions): Promise { - if (pnpmSyncJsonPath === "") { + if (pnpmSyncJsonPath === '') { // if user does not input .pnpm-sync.json file path // then we assume .pnpm-sync.json is always under node_modules folder - pnpmSyncJsonPath = "node_modules/.pnpm-sync.json"; + pnpmSyncJsonPath = 'node_modules/.pnpm-sync.json'; } let pnpmSyncJsonContents: string; try { - pnpmSyncJsonContents = ( - await fs.promises.readFile(pnpmSyncJsonPath) - ).toString(); + pnpmSyncJsonContents = (await fs.promises.readFile(pnpmSyncJsonPath)).toString(); } catch (e) { - if ((e as NodeJS.ErrnoException).code === "ENOENT") { + if ((e as NodeJS.ErrnoException).code === 'ENOENT') { console.warn( - "You are executing pnpm-sync for a package, but we can not find the .pnpm-sync.json inside node_modules folder" + 'You are executing pnpm-sync for a package, but we can not find the .pnpm-sync.json inside node_modules folder' ); return; } else { @@ -64,16 +62,11 @@ export async function pnpmSyncCopyAsync({ //get npmPackFiles const npmPackFiles: string[] = await getPackageIncludedFiles(sourcePath); - console.time( - `pnpm-sync => ${sourcePath}, total ${npmPackFiles.length} files` - ); + console.time(`pnpm-sync => ${sourcePath}, total ${npmPackFiles.length} files`); //clear the destination folder first for (const targetFolder of targetFolders) { - const destinationPath = path.resolve( - pnpmSyncJsonPath, - targetFolder.folderPath - ); + const destinationPath = path.resolve(pnpmSyncJsonPath, targetFolder.folderPath); await fs.promises.rm(destinationPath, { recursive: true }); } @@ -81,16 +74,10 @@ export async function pnpmSyncCopyAsync({ npmPackFiles, async (npmPackFile: string) => { for (const targetFolder of targetFolders) { - const destinationPath = path.resolve( - pnpmSyncJsonPath, - targetFolder.folderPath - ); + const destinationPath = path.resolve(pnpmSyncJsonPath, targetFolder.folderPath); const copySourcePath: string = path.join(sourcePath, npmPackFile); - const copyDestinationPath: string = path.join( - destinationPath, - npmPackFile - ); + const copyDestinationPath: string = path.join(destinationPath, npmPackFile); await ensureFolder(path.dirname(copyDestinationPath)); @@ -99,11 +86,9 @@ export async function pnpmSyncCopyAsync({ } }, { - concurrency: 10, + concurrency: 10 } ); - console.timeEnd( - `pnpm-sync => ${sourcePath}, total ${npmPackFiles.length} files` - ); + console.timeEnd(`pnpm-sync => ${sourcePath}, total ${npmPackFiles.length} files`); } diff --git a/packages/pnpm-sync-lib/src/pnpmSyncPrepare.ts b/packages/pnpm-sync-lib/src/pnpmSyncPrepare.ts index 0c7e91a..d0b95ce 100644 --- a/packages/pnpm-sync-lib/src/pnpmSyncPrepare.ts +++ b/packages/pnpm-sync-lib/src/pnpmSyncPrepare.ts @@ -1,8 +1,8 @@ -import path from "path"; -import fs from "fs"; -import { cwd } from "process"; +import path from 'path'; +import fs from 'fs'; +import { cwd } from 'process'; -import type { ILockfile, IPnpmSyncJson, IVersionSpecifier } from "./interfaces"; +import type { ILockfile, IPnpmSyncJson, IVersionSpecifier } from './interfaces'; /** * @beta @@ -30,79 +30,56 @@ export interface IPnpmSyncPrepareOptions { export async function pnpmSyncPrepareAsync({ lockfilePath, storePath, - readPnpmLockfile, + readPnpmLockfile }: IPnpmSyncPrepareOptions): Promise { - console.log("Generate pnpm-sync.json ..."); + console.log('Generate pnpm-sync.json ...'); // get the pnpm-lock.yaml path lockfilePath = path.resolve(cwd(), lockfilePath); storePath = path.resolve(cwd(), storePath); - console.log("The pnpm-lock.yaml file path =>", lockfilePath); - console.log("The .pnpm folder path =>", storePath); + console.log('The pnpm-lock.yaml file path =>', lockfilePath); + console.log('The .pnpm folder path =>', storePath); if (!fs.existsSync(lockfilePath)) { - throw Error("The input pnpm-lock.yaml path is not correct!"); + throw Error('The input pnpm-lock.yaml path is not correct!'); } console.time(`pnpm-sync prepare`); // read the pnpm-lock.yaml const pnpmLockfile = await readPnpmLockfile(lockfilePath, { - ignoreIncompatible: true, + ignoreIncompatible: true }); // find injected dependency and all its available versions - const injectedDependencyToVersion: Map< - string, - Set - > = getInjectedDependencyToVersion(pnpmLockfile); + const injectedDependencyToVersion: Map> = getInjectedDependencyToVersion(pnpmLockfile); // get pnpm-lock.yaml folder path - const pnpmLockFolder = lockfilePath.slice( - 0, - lockfilePath.length - "pnpm-lock.yaml".length - ); + const pnpmLockFolder = lockfilePath.slice(0, lockfilePath.length - 'pnpm-lock.yaml'.length); // generate a map, where key is the actual path of the injectedDependency, value is all available paths in .pnpm folder const injectedDependencyToFilePathSet: Map> = new Map(); - for (const [ - injectedDependency, - injectedDependencyVersionSet, - ] of injectedDependencyToVersion) { + for (const [injectedDependency, injectedDependencyVersionSet] of injectedDependencyToVersion) { for (const injectedDependencyVersion of injectedDependencyVersionSet) { // this logic is heavily depends on pnpm-lock formate // the current logic is for pnpm v8 // for example: file:../../libraries/lib1(react@16.0.0) -> ../../libraries/lib1 - let injectedDependencyPath = injectedDependencyVersion - .split("(")[0] - .slice("file:".length); - injectedDependencyPath = path.resolve( - pnpmLockFolder, - injectedDependencyPath - ); + let injectedDependencyPath = injectedDependencyVersion.split('(')[0].slice('file:'.length); + injectedDependencyPath = path.resolve(pnpmLockFolder, injectedDependencyPath); if (!injectedDependencyToFilePathSet.has(injectedDependencyPath)) { injectedDependencyToFilePathSet.set(injectedDependencyPath, new Set()); } injectedDependencyToFilePathSet .get(injectedDependencyPath) - ?.add( - transferFilePathToPnpmStorePath( - injectedDependencyVersion, - injectedDependency, - storePath - ) - ); + ?.add(transferFilePathToPnpmStorePath(injectedDependencyVersion, injectedDependency, storePath)); } } // now, we have everything we need to generate the the pnpm-sync.json // console.log('injectedDependencyToFilePathSet =>', injectedDependencyToFilePathSet); - for (const [ - projectFolder, - targetFolderSet, - ] of injectedDependencyToFilePathSet) { + for (const [projectFolder, targetFolderSet] of injectedDependencyToFilePathSet) { if (targetFolderSet.size === 0) { continue; } @@ -111,22 +88,19 @@ export async function pnpmSyncPrepareAsync({ let pnpmSyncJsonFile: IPnpmSyncJson = { postbuildInjectedCopy: { - sourceFolder: "../..", - targetFolders: [], - }, + sourceFolder: '../..', + targetFolders: [] + } }; // if .pnpm-sync.json already exists, read it first if (fs.existsSync(pnpmSyncJsonPath)) { - pnpmSyncJsonFile = JSON.parse( - fs.readFileSync(pnpmSyncJsonPath).toString() - ); + pnpmSyncJsonFile = JSON.parse(fs.readFileSync(pnpmSyncJsonPath).toString()); } const existingTargetFolderSet: Set = new Set(); - for (const targetFolder of pnpmSyncJsonFile.postbuildInjectedCopy - .targetFolders) { + for (const targetFolder of pnpmSyncJsonFile.postbuildInjectedCopy.targetFolders) { existingTargetFolderSet.add(targetFolder.folderPath); } @@ -134,14 +108,11 @@ export async function pnpmSyncPrepareAsync({ const relativePath = path.relative(pnpmSyncJsonPath, targetFolder); if (!existingTargetFolderSet.has(relativePath)) { pnpmSyncJsonFile.postbuildInjectedCopy.targetFolders.push({ - folderPath: relativePath, + folderPath: relativePath }); } } - fs.writeFileSync( - pnpmSyncJsonPath, - JSON.stringify(pnpmSyncJsonFile, null, 2) - ); + fs.writeFileSync(pnpmSyncJsonPath, JSON.stringify(pnpmSyncJsonFile, null, 2)); } console.timeEnd(`pnpm-sync prepare`); } @@ -157,36 +128,33 @@ function transferFilePathToPnpmStorePath( // an example, file:../../libraries/lib1(react@16.0.0) -> file+..+..+libraries+lib1_react@16.9.0 // 1. replace ':' with '+' - rawFilePath = rawFilePath.replaceAll(":", "+"); + rawFilePath = rawFilePath.replaceAll(':', '+'); // 2. replace '/' with '+' - rawFilePath = rawFilePath.replaceAll("/", "+"); + rawFilePath = rawFilePath.replaceAll('/', '+'); // 3. replace '(' with '_' - rawFilePath = rawFilePath.replaceAll("(", "_"); + rawFilePath = rawFilePath.replaceAll('(', '_'); // 4. remove ')' - rawFilePath = rawFilePath.replaceAll(")", ""); + rawFilePath = rawFilePath.replaceAll(')', ''); // 5. add dependencyName rawFilePath = rawFilePath + `/node_modules/${dependencyName}`; - rawFilePath = storePath + "/" + rawFilePath; + rawFilePath = storePath + '/' + rawFilePath; return rawFilePath; } // process dependencies and devDependencies to generate injectedDependencyToFilePath -function getInjectedDependencyToVersion( - pnpmLockfile: ILockfile | undefined -): Map> { +function getInjectedDependencyToVersion(pnpmLockfile: ILockfile | undefined): Map> { const injectedDependencyToVersion: Map> = new Map(); for (const importerKey in pnpmLockfile?.importers) { if (!pnpmLockfile?.importers[importerKey]?.dependenciesMeta) { continue; } - const dependenciesMeta = - pnpmLockfile?.importers[importerKey]?.dependenciesMeta; + const dependenciesMeta = pnpmLockfile?.importers[importerKey]?.dependenciesMeta; for (const dependency in dependenciesMeta) { if (dependenciesMeta[dependency]?.injected) { @@ -198,14 +166,8 @@ function getInjectedDependencyToVersion( // based on https://pnpm.io/package_json#dependenciesmeta // the injected dependencies could available inside dependencies, optionalDependencies, and devDependencies. - processDependencies( - pnpmLockfile?.importers[importerKey]?.dependencies, - injectedDependencyToVersion - ); - processDependencies( - pnpmLockfile?.importers[importerKey]?.devDependencies, - injectedDependencyToVersion - ); + processDependencies(pnpmLockfile?.importers[importerKey]?.dependencies, injectedDependencyToVersion); + processDependencies(pnpmLockfile?.importers[importerKey]?.devDependencies, injectedDependencyToVersion); processDependencies( pnpmLockfile?.importers[importerKey]?.optionalDependencies, injectedDependencyToVersion @@ -220,8 +182,7 @@ function processDependencies( if (dependencies) { for (const [dependency, specifier] of Object.entries(dependencies)) { if (injectedDependencyToVersion.has(dependency)) { - const specifierToUse: string = - typeof specifier === "string" ? specifier : specifier.version; + const specifierToUse: string = typeof specifier === 'string' ? specifier : specifier.version; injectedDependencyToVersion.get(dependency)?.add(specifierToUse); } } diff --git a/packages/pnpm-sync-lib/tsconfig.json b/packages/pnpm-sync-lib/tsconfig.json index eb50b80..5aec6d2 100644 --- a/packages/pnpm-sync-lib/tsconfig.json +++ b/packages/pnpm-sync-lib/tsconfig.json @@ -2,8 +2,6 @@ "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { "types": ["heft-jest", "node"], - "lib": [ - "ES2021.String" - ] + "lib": ["ES2021.String"] } } diff --git a/packages/pnpm-sync/.eslintrc.js b/packages/pnpm-sync/.eslintrc.js index 246aa14..e11197c 100644 --- a/packages/pnpm-sync/.eslintrc.js +++ b/packages/pnpm-sync/.eslintrc.js @@ -1,5 +1,5 @@ -require("@rushstack/eslint-patch/modern-module-resolution"); +require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: ['@rushstack/eslint-config/profile/node'], parserOptions: { tsconfigRootDir: __dirname } -}; \ No newline at end of file +}; diff --git a/packages/pnpm-sync/src/start.ts b/packages/pnpm-sync/src/start.ts index 06f3a47..d884bfd 100644 --- a/packages/pnpm-sync/src/start.ts +++ b/packages/pnpm-sync/src/start.ts @@ -1,57 +1,52 @@ -import { Command } from "commander"; -import { pnpmSyncCopyAsync, pnpmSyncPrepareAsync } from "pnpm-sync-lib"; -import { FileSystem, Async } from "@rushstack/node-core-library"; -import { PackageExtractor } from "@rushstack/package-extractor"; -import { readWantedLockfile, Lockfile } from "@pnpm/lockfile-file"; +import { Command } from 'commander'; +import { pnpmSyncCopyAsync, pnpmSyncPrepareAsync } from 'pnpm-sync-lib'; +import { FileSystem, Async } from '@rushstack/node-core-library'; +import { PackageExtractor } from '@rushstack/package-extractor'; +import { readWantedLockfile, Lockfile } from '@pnpm/lockfile-file'; const program: Command = new Command(); -program.version(require("../package.json").version); +program.version(require('../package.json').version); program - .command("copy") - .description( - "Execute the copy action based on the plan defined under node_modules/.pnpm-sync.json" - ) + .command('copy') + .description('Execute the copy action based on the plan defined under node_modules/.pnpm-sync.json') .action( async () => await pnpmSyncCopyAsync({ getPackageIncludedFiles: PackageExtractor.getPackageIncludedFilesAsync, forEachAsyncWithConcurrency: Async.forEachAsync, - ensureFolder: FileSystem.ensureFolderAsync, + ensureFolder: FileSystem.ensureFolderAsync }) ); program - .command("prepare") - .description( - "Generate the pnpm-sync.json based on pnpm-lock.yaml file path and .pnpm folder path" - ) - .requiredOption("-l, --lockfile ", "The pnpm-lock.yaml file path") - .requiredOption("-s, --store ", "The .pnpm folder path") + .command('prepare') + .description('Generate the pnpm-sync.json based on pnpm-lock.yaml file path and .pnpm folder path') + .requiredOption('-l, --lockfile ', 'The pnpm-lock.yaml file path') + .requiredOption('-s, --store ', 'The .pnpm folder path') .action(async (options) => { const { lockfile, store } = options; try { await pnpmSyncPrepareAsync({ lockfilePath: lockfile, storePath: store, - readPnpmLockfile: async (lockfilePath: string, options: { - ignoreIncompatible: boolean - }) => { - - const pnpmLockFolder = lockfilePath.slice( - 0, - lockfilePath.length - "pnpm-lock.yaml".length - ); + readPnpmLockfile: async ( + lockfilePath: string, + options: { + ignoreIncompatible: boolean; + } + ) => { + const pnpmLockFolder = lockfilePath.slice(0, lockfilePath.length - 'pnpm-lock.yaml'.length); const lockfile: Lockfile | null = await readWantedLockfile(pnpmLockFolder, options); - if(lockfile === null){ + if (lockfile === null) { return undefined; } else { - return lockfile + return lockfile; } - }, + } }); } catch (error) { console.log(error); diff --git a/pnpm-sync-cli-demo/app1/src/index.ts b/pnpm-sync-cli-demo/app1/src/index.ts index f15f02b..f402146 100644 --- a/pnpm-sync-cli-demo/app1/src/index.ts +++ b/pnpm-sync-cli-demo/app1/src/index.ts @@ -1,3 +1,3 @@ export function app1() { return 'This is from app1'; -} \ No newline at end of file +} diff --git a/pnpm-sync-cli-demo/app1/tsconfig.json b/pnpm-sync-cli-demo/app1/tsconfig.json index d4c971b..dfbd665 100644 --- a/pnpm-sync-cli-demo/app1/tsconfig.json +++ b/pnpm-sync-cli-demo/app1/tsconfig.json @@ -10,9 +10,7 @@ "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, "moduleResolution": "node16", - "types": [ - "node" - ] + "types": ["node"] }, "include": ["src"] -} \ No newline at end of file +} diff --git a/pnpm-sync-cli-demo/app2/src/index.ts b/pnpm-sync-cli-demo/app2/src/index.ts index c393e8b..ddd9ddc 100644 --- a/pnpm-sync-cli-demo/app2/src/index.ts +++ b/pnpm-sync-cli-demo/app2/src/index.ts @@ -1,3 +1,3 @@ export function app2() { return 'This is from app2'; -} \ No newline at end of file +} diff --git a/pnpm-sync-cli-demo/app2/tsconfig.json b/pnpm-sync-cli-demo/app2/tsconfig.json index d4c971b..dfbd665 100644 --- a/pnpm-sync-cli-demo/app2/tsconfig.json +++ b/pnpm-sync-cli-demo/app2/tsconfig.json @@ -10,9 +10,7 @@ "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, "moduleResolution": "node16", - "types": [ - "node" - ] + "types": ["node"] }, "include": ["src"] -} \ No newline at end of file +} diff --git a/pnpm-sync-cli-demo/lib1/src/index.ts b/pnpm-sync-cli-demo/lib1/src/index.ts index 131f5d8..23cc297 100644 --- a/pnpm-sync-cli-demo/lib1/src/index.ts +++ b/pnpm-sync-cli-demo/lib1/src/index.ts @@ -1,3 +1,3 @@ export function lib1() { return 'This is from lib1'; -} \ No newline at end of file +} diff --git a/pnpm-sync-cli-demo/lib1/tsconfig.json b/pnpm-sync-cli-demo/lib1/tsconfig.json index 6f02b06..9bca3ae 100644 --- a/pnpm-sync-cli-demo/lib1/tsconfig.json +++ b/pnpm-sync-cli-demo/lib1/tsconfig.json @@ -12,9 +12,7 @@ "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, "moduleResolution": "node16", - "types": [ - "node" - ] + "types": ["node"] }, "include": ["src"] -} \ No newline at end of file +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5bcf20f..212d8d2 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,4 @@ packages: - 'packages/*' - 'pnpm-sync-api-demo/*' - - 'pnpm-sync-cli-demo/*' \ No newline at end of file + - 'pnpm-sync-cli-demo/*'