diff --git a/src/add.ts b/src/add.ts index 72f12e2..0b789fe 100644 --- a/src/add.ts +++ b/src/add.ts @@ -24,6 +24,7 @@ export interface AddPackagesOptions { dev?: boolean link?: boolean linkDep?: boolean + portalDep?: boolean replace?: boolean update?: boolean safe?: boolean @@ -58,6 +59,18 @@ const checkPnpmWorkspace = (workingDir: string) => { return fs.existsSync(join(workingDir, 'pnpm-workspace.yaml')) } +const getProtocol = (options: { linkDep?: boolean, portalDep?: boolean }) => { + if (options.portalDep) { + return 'portal:'; + } + + if (options.linkDep) { + return 'link:'; + } + + return 'file:'; +} + export const addPackages = async ( packages: string[], options: AddPackagesOptions @@ -84,6 +97,7 @@ export const addPackages = async ( let pnpmWorkspace = false + const isLinkLike = options.link || options.linkDep || options.portalDep; const doPure = options.pure === false ? false @@ -162,20 +176,21 @@ export const addPackages = async ( )} purely` ) } + if (!doPure) { const destModulesDir = join(workingDir, 'node_modules', name) - if (options.link || options.linkDep || isSymlink(destModulesDir)) { + if (isLinkLike && isSymlink(destModulesDir)) { fs.removeSync(destModulesDir) } - if (options.link || options.linkDep) { + if (isLinkLike) { ensureSymlinkSync(destYalcCopyDir, destModulesDir, 'junction') } else { await copyDirSafe(destYalcCopyDir, destModulesDir, !options.replace) } if (!options.link) { - const protocol = options.linkDep ? 'link:' : 'file:' + const protocol = getProtocol(options); const localAddress = options.workspace ? 'workspace:*' : protocol + values.yalcPackagesFolder + '/' + pkg.name @@ -211,7 +226,7 @@ export const addPackages = async ( replacedVersion = replacedVersion == localAddress ? '' : replacedVersion } - if (pkg.bin && (options.link || options.linkDep)) { + if (pkg.bin && isLinkLike) { const binDir = join(workingDir, 'node_modules', '.bin') const addBinScript = (src: string, dest: string) => { const srcPath = join(destYalcCopyDir, src) @@ -274,8 +289,9 @@ export const addPackages = async ( workspace: options.workspace, file: options.workspace ? undefined - : !options.link && !options.linkDep && !doPure, - link: options.linkDep && !doPure, + : !isLinkLike && !doPure, + link: !options.portalDep && options.linkDep && !doPure, + portal: options.portalDep && !doPure, signature: i.signature, })), { workingDir: options.workingDir } diff --git a/src/lockfile.ts b/src/lockfile.ts index 09f7b9c..544409b 100644 --- a/src/lockfile.ts +++ b/src/lockfile.ts @@ -14,6 +14,7 @@ export type LockFilePackageEntry = { version?: string file?: boolean link?: boolean + portal?: boolean replaced?: string signature?: string pure?: boolean @@ -90,7 +91,7 @@ export const addPackageToLockfile = ( ) => { const lockfile = readLockfile(options) packages.forEach( - ({ name, version, file, link, replaced, signature, pure, workspace }) => { + ({ name, version, file, link, portal, replaced, signature, pure, workspace }) => { let old = lockfile.packages[name] || {} lockfile.packages[name] = {} if (version) { @@ -105,6 +106,9 @@ export const addPackageToLockfile = ( if (link) { lockfile.packages[name].link = true } + if (portal) { + lockfile.packages[name].portal = true + } if (pure) { lockfile.packages[name].pure = true } diff --git a/src/update.ts b/src/update.ts index 1f7d44d..ea83c05 100644 --- a/src/update.ts +++ b/src/update.ts @@ -48,6 +48,7 @@ export const updatePackages = async ( file: lockfile.packages[name].file, link: lockfile.packages[name].link, pure: lockfile.packages[name].pure, + portal: lockfile.packages[name].portal, workspace: lockfile.packages[name].workspace, })) @@ -68,7 +69,7 @@ export const updatePackages = async ( }) const packagesLinks = lockPackages - .filter((p) => !p.file && !p.link && !p.pure && !p.workspace) + .filter((p) => !p.file && !p.link && !p.portal && !p.pure && !p.workspace) .map((p) => p.name) await addPackages(packagesLinks, { ...addOpts, @@ -83,6 +84,13 @@ export const updatePackages = async ( pure: false, }) + const packagesPortalDep = lockPackages.filter((p) => p.portal).map((p) => p.name) + await addPackages(packagesPortalDep, { + ...addOpts, + portalDep: true, + pure: false, + }) + const packagesLinkDep = lockPackages.filter((p) => p.link).map((p) => p.name) await addPackages(packagesLinkDep, { ...addOpts, diff --git a/src/yalc.ts b/src/yalc.ts index ac934c4..d8ce96b 100644 --- a/src/yalc.ts +++ b/src/yalc.ts @@ -154,7 +154,7 @@ yargs describe: 'Add package from yalc repo to the project', builder: () => { return yargs - .boolean(['file', 'dev', 'link', ...updateFlags]) + .boolean(['file', 'dev', 'link', 'portal', ...updateFlags]) .alias('D', 'dev') .boolean('workspace') .alias('save-dev', 'dev') @@ -166,6 +166,7 @@ yargs return addPackages(argv._.slice(1), { dev: argv.dev, linkDep: argv.link, + portalDep: argv.portal, restore: argv.restore, pure: argv.pure, workspace: argv.workspace, diff --git a/test/index.ts b/test/index.ts index 169a3de..68a3dc6 100644 --- a/test/index.ts +++ b/test/index.ts @@ -514,4 +514,74 @@ describe('Yalc package manager', function () { }) }) }) + + describe('Add package (--portal)', () => { + before(() => { + return addPackages([values.depPackage], { + workingDir: projectDir, + portalDep: true, + }) + }) + it('copies package to .yalc folder', () => { + checkExists(join(projectDir, '.yalc', values.depPackage)) + }) + it('copies remove package to node_modules', () => { + checkExists(join(projectDir, 'node_modules', values.depPackage)) + }) + it('creates to yalc.lock', () => { + checkExists(join(projectDir, 'yalc.lock')) + }) + it('places yalc.lock correct info about file', () => { + const lockFile = readLockfile({ workingDir: projectDir }) + deepEqual(lockFile.packages, { + [values.depPackage]: { + portal: true, + replaced: 'link:.yalc/' + values.depPackage, + signature: extractSignature(lockFile, values.depPackage), + }, + }) + }) + it('updates package.json', () => { + const pkg = readPackageManifest(projectDir)! + deepEqual(pkg.dependencies, { + [values.depPackage]: 'portal:.yalc/' + values.depPackage, + }) + }) + it('create and updates installations file', () => { + const installtions = readInstallationsFile() + deepEqual(installtions, { + [values.depPackage]: [projectDir], + }) + }) + }) + + describe('Updated linked (--portal) package', () => { + before(() => { + return updatePackages([values.depPackage], { + workingDir: projectDir, + }) + }) + it('places yalc.lock correct info about file', () => { + const lockFile = readLockfile({ workingDir: projectDir }) + deepEqual(lockFile.packages, { + [values.depPackage]: { + portal: true, + replaced: 'link:.yalc/' + values.depPackage, + signature: extractSignature(lockFile, values.depPackage), + }, + }) + }) + it('updates package.json', () => { + const pkg = readPackageManifest(projectDir)! + deepEqual(pkg.dependencies, { + [values.depPackage]: 'portal:.yalc/' + values.depPackage, + }) + }) + it('create and updates installations file', () => { + const installtions = readInstallationsFile() + deepEqual(installtions, { + [values.depPackage]: [projectDir], + }) + }) + }) })