@@ -52,6 +52,7 @@ async function packPlugin(params: {
5252 pluginId : string ;
5353 version : string ;
5454 rootDir : string ;
55+ indexJs ?: string ;
5556} ) : Promise < PackedVersion > {
5657 const packageDir = path . join ( params . rootDir , `package-${ params . packageName } -${ params . version } ` ) ;
5758 const peerDependenciesMeta = params . peerDependencies
@@ -94,7 +95,11 @@ async function packPlugin(params: {
9495 ) } \n`,
9596 "utf8" ,
9697 ) ;
97- await fs . writeFile ( path . join ( packageDir , "dist" , "index.js" ) , "export {};\n" , "utf8" ) ;
98+ await fs . writeFile (
99+ path . join ( packageDir , "dist" , "index.js" ) ,
100+ params . indexJs ?? "export {};\n" ,
101+ "utf8" ,
102+ ) ;
98103
99104 const packOutput = execFileSync (
100105 "npm" ,
@@ -439,6 +444,102 @@ describe("installPluginFromNpmSpec e2e", () => {
439444 ) . resolves . toBeTruthy ( ) ;
440445 } ) ;
441446
447+ it ( "does not attribute repaired pre-existing peer dependencies to later installs" , async ( ) => {
448+ const rootDir = await makeTempDir ( "npm-plugin-repaired-peer-scan-e2e" ) ;
449+ const npmRoot = path . join ( rootDir , "managed-npm" ) ;
450+ const pluginWithRuntimePeer = `existing-peer-plugin-${ crypto . randomUUID ( ) . replace ( / - / g, "" ) . slice ( 0 , 12 ) } ` ;
451+ const laterPlugin = `later-plugin-${ crypto . randomUUID ( ) . replace ( / - / g, "" ) . slice ( 0 , 12 ) } ` ;
452+ const runtimePeer = `runtime-peer-${ crypto . randomUUID ( ) . replace ( / - / g, "" ) . slice ( 0 , 12 ) } ` ;
453+ const registry = await startStaticRegistry ( [
454+ {
455+ packageName : pluginWithRuntimePeer ,
456+ latest : "1.0.0" ,
457+ versions : [
458+ await packPlugin ( {
459+ packageName : pluginWithRuntimePeer ,
460+ peerDependencies : { [ runtimePeer ] : "^1.0.0" } ,
461+ peerDependenciesMeta : { } ,
462+ pluginId : pluginWithRuntimePeer ,
463+ version : "1.0.0" ,
464+ rootDir,
465+ } ) ,
466+ ] ,
467+ } ,
468+ {
469+ packageName : laterPlugin ,
470+ latest : "1.0.0" ,
471+ versions : [
472+ await packPlugin ( {
473+ packageName : laterPlugin ,
474+ pluginId : laterPlugin ,
475+ version : "1.0.0" ,
476+ rootDir,
477+ } ) ,
478+ ] ,
479+ } ,
480+ {
481+ packageName : runtimePeer ,
482+ latest : "1.0.0" ,
483+ versions : [
484+ await packPlugin ( {
485+ indexJs : "eval('1');\n" ,
486+ packageName : runtimePeer ,
487+ pluginId : runtimePeer ,
488+ version : "1.0.0" ,
489+ rootDir,
490+ } ) ,
491+ ] ,
492+ } ,
493+ ] ) ;
494+ process . env . NPM_CONFIG_REGISTRY = registry ;
495+ process . env . npm_config_registry = registry ;
496+
497+ await fs . mkdir ( npmRoot , { recursive : true } ) ;
498+ await fs . writeFile (
499+ path . join ( npmRoot , "package.json" ) ,
500+ `${ JSON . stringify (
501+ {
502+ private : true ,
503+ dependencies : { [ pluginWithRuntimePeer ] : "1.0.0" } ,
504+ } ,
505+ null ,
506+ 2 ,
507+ ) } \n`,
508+ "utf8" ,
509+ ) ;
510+ await execFileAsync (
511+ "npm" ,
512+ [
513+ "install" ,
514+ "--omit=dev" ,
515+ "--omit=peer" ,
516+ "--legacy-peer-deps" ,
517+ "--loglevel=error" ,
518+ "--ignore-scripts" ,
519+ "--no-audit" ,
520+ "--no-fund" ,
521+ ] ,
522+ { cwd : npmRoot } ,
523+ ) ;
524+ await expect (
525+ fs . lstat ( path . join ( npmRoot , "node_modules" , runtimePeer , "package.json" ) ) ,
526+ ) . rejects . toHaveProperty ( "code" , "ENOENT" ) ;
527+
528+ const later = await installPluginFromNpmSpec ( {
529+ spec : `${ laterPlugin } @1.0.0` ,
530+ npmDir : npmRoot ,
531+ logger : { info : ( ) => { } , warn : ( ) => { } } ,
532+ timeoutMs : 120_000 ,
533+ } ) ;
534+ if ( ! later . ok ) {
535+ throw new Error ( later . error ) ;
536+ }
537+
538+ await expect (
539+ fs . lstat ( path . join ( npmRoot , "node_modules" , runtimePeer , "package.json" ) ) ,
540+ ) . resolves . toBeTruthy ( ) ;
541+ } ) ;
542+
442543 it ( "scrubs host peers when installing beside an existing host-peer plugin" , async ( ) => {
443544 const rootDir = await makeTempDir ( "npm-plugin-sibling-peer-e2e" ) ;
444545 const npmRoot = path . join ( rootDir , "managed-npm" ) ;
0 commit comments