@@ -34,8 +34,9 @@ const parsePositional = (arg) => {
3434 return { name, range : null }
3535}
3636
37- // Shared implementation for `npm approve-scripts` and `npm deny-scripts`.
38- // Subclasses set `verb` to `'approve'` or `'deny'`.
37+ // Shared implementation for `npm approve-scripts`, `npm deny-scripts`, and the `npm install-scripts` namespace.
38+ // `npm install-scripts` dispatches to `runMode('approve' | 'deny' | 'list', ...)`.
39+ // The standalone commands set `static verb` and run through the default `exec`.
3940//
4041// Extends `BaseCommand` rather than `ArboristCmd` on purpose. Per RFC,
4142// `allowScripts` is read from the workspace root's `package.json` only;
@@ -48,33 +49,51 @@ class AllowScriptsCmd extends BaseCommand {
4849 static params = [ 'all' , 'allow-scripts-pending' , 'allow-scripts-pin' , 'json' ]
4950 static ignoreImplicitWorkspace = false
5051
51- // Subclasses set `static verb = 'approve' | 'deny'`.
52+ // Mode of the current run, set by runMode.
53+ // One of 'approve', 'deny', or 'list'.
54+ #mode = null
55+
56+ // verb drives the writers and summaries, which only run in the two write modes, so it is never read while listing.
5257 get verb ( ) {
53- /* istanbul ignore next: every concrete subclass declares static verb */
54- return this . constructor . verb
58+ return this . #mode
5559 }
5660
61+ // Standalone `npm approve-scripts` / `npm deny-scripts` pick their mode from `static verb`.
5762 async exec ( args ) {
63+ return this . runMode ( this . constructor . verb , args )
64+ }
65+
66+ async runMode ( mode , args ) {
67+ this . #mode = mode
68+
5869 if ( this . npm . global ) {
5970 throw Object . assign (
6071 new Error ( `\`npm ${ this . constructor . name } \` does not work for global installs` ) ,
6172 { code : 'EGLOBAL' }
6273 )
6374 }
6475
65- const pending = ! ! this . npm . config . get ( 'allow-scripts-pending' )
76+ // `--allow-scripts-pending` is only honored by commands that declare it; the namespace lists via `ls` instead.
77+ const pending = this . constructor . params . includes ( 'allow-scripts-pending' ) &&
78+ ! ! this . npm . config . get ( 'allow-scripts-pending' )
6679 const all = ! ! this . npm . config . get ( 'all' )
80+ // The `ls` subcommand lists, and so does `--allow-scripts-pending` on the write commands.
81+ const list = mode === 'list' || pending
6782
68- if ( pending && ( args . length > 0 || all ) ) {
83+ if ( list && ( args . length > 0 || all ) ) {
84+ const what = mode === 'list' ? '`npm install-scripts ls`' : '`--allow-scripts-pending`'
6985 throw this . usageError (
70- '`--allow-scripts-pending` cannot be combined with positional arguments or `--all`.'
86+ ` ${ what } cannot be combined with positional arguments or \ `--all\`.`
7187 )
7288 }
73- if ( ! pending && ! all && args . length === 0 ) {
89+ if ( ! list && ! all && args . length === 0 ) {
7490 throw this . usageError ( )
7591 }
76- if ( this . verb === 'deny' && pending ) {
77- throw this . usageError ( '`npm deny-scripts --allow-scripts-pending` is not supported.' )
92+ if ( mode === 'deny' && pending ) {
93+ throw this . usageError (
94+ '`npm deny-scripts --allow-scripts-pending` is not supported; ' +
95+ 'run `npm install-scripts ls` to list unreviewed packages.'
96+ )
7897 }
7998
8099 const Arborist = require ( '@npmcli/arborist' )
@@ -91,7 +110,7 @@ class AllowScriptsCmd extends BaseCommand {
91110 // only lists; nothing runs.
92111 const unreviewed = await checkAllowScripts ( { arb, npm : this . npm , includeWhenIgnored : true } )
93112
94- if ( pending ) {
113+ if ( list ) {
95114 return this . runPending ( unreviewed )
96115 }
97116
@@ -129,7 +148,8 @@ class AllowScriptsCmd extends BaseCommand {
129148 }
130149 output . standard ( '' )
131150 output . standard (
132- 'Run `npm approve-scripts <pkg>` to allow, or `npm deny-scripts <pkg>` to deny.'
151+ 'Run `npm install-scripts approve <pkg>` to allow, ' +
152+ 'or `npm install-scripts deny <pkg>` to deny.'
133153 )
134154 }
135155
0 commit comments