Skip to content

Commit a2a2715

Browse files
committed
feat(packages): support pnpm and yarn projects (fixes jesseduffield#14)
1 parent 339df27 commit a2a2715

32 files changed

Lines changed: 838 additions & 311 deletions

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ Call `lazynpm` in your terminal inside a git repository.
7373
$ lazynpm
7474
```
7575

76+
lazynpm detects npm, pnpm, or Yarn from the project's lockfile and
77+
`packageManager` field. Override detection with `NODE_PKG_MANAGER=yarn lazynpm`
78+
or `lazynpm --package-manager yarn`. The `packageManager` config option provides
79+
the same override for every launch.
80+
7681
If you want, you can
7782
also add an alias for this with `echo "alias lzn='lazynpm'" >> ~/.zshrc` (or
7883
whichever rc file you're using).

docs/Config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Default path for the config file:
88
## Default
99

1010
```yaml
11+
packageManager: '' # npm, pnpm, or yarn; empty means auto-detect
1112
gui:
1213
# stuff relating to the UI
1314
scrollHeight: 2 # how many lines you scroll by

docs/keybindings/Keybindings_en.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
## Dependencies Panel
1616

1717
<pre>
18-
<kbd>i</kbd>: [33m`npm install`[0m dependency
18+
<kbd>i</kbd>: install dependency
1919
<kbd>o</kbd>: open package.json
20-
<kbd>u</kbd>: [33m`npm update`[0m dependency
20+
<kbd>u</kbd>: update dependency
2121
<kbd>d</kbd>: `npm uninstall` dependency
2222
<kbd>t</kbd>: change dependency type (prod/dev/optional)
23-
<kbd>n</kbd>: [33m`npm install`[0m new dependency
23+
<kbd>n</kbd>: install new dependency
2424
<kbd>e</kbd>: edit dependency constraint
2525
<kbd>,</kbd>: previous page
2626
<kbd>.</kbd>: next page
@@ -45,12 +45,12 @@
4545

4646
<pre>
4747
<kbd>n</kbd>: add package to list
48-
<kbd>p</kbd>: [33m`npm pack`[0m package
49-
<kbd>l</kbd>: [33m`npm link <package>`[0m (or unlink if already linked)
50-
<kbd>L</kbd>: [33m`npm link`[0m (i.e. globally link) (or unlink if already linked)
48+
<kbd>p</kbd>: pack package
49+
<kbd>l</kbd>: link package (or unlink if already linked)
50+
<kbd>L</kbd>: globally link package (or unlink if already linked)
5151
<kbd>d</kbd>: remove package from list
52-
<kbd>i</kbd>: [33m`npm install`[0m package
53-
<kbd>b</kbd>: [33m`npm run build`[0m package
52+
<kbd>i</kbd>: install package dependencies
53+
<kbd>b</kbd>: build package
5454
<kbd>o</kbd>: open package.json
5555
<kbd>,</kbd>: previous page
5656
<kbd>.</kbd>: next page
@@ -62,7 +62,7 @@
6262
## Scripts Panel
6363

6464
<pre>
65-
<kbd>space</kbd>: [33m`npm run`[0m script
65+
<kbd>space</kbd>: run script
6666
<kbd>d</kbd>: remove script from package.json
6767
<kbd>e</kbd>: edit script
6868
<kbd>n</kbd>: add script
@@ -85,8 +85,8 @@
8585

8686
<pre>
8787
<kbd>d</kbd>: delete tarball
88-
<kbd>i</kbd>: [33m`npm install`[0m tarball
89-
<kbd>P</kbd>: [33m`npm publish`[0m tarball
88+
<kbd>i</kbd>: install tarball
89+
<kbd>P</kbd>: publish tarball
9090
<kbd>,</kbd>: previous page
9191
<kbd>.</kbd>: next page
9292
<kbd><</kbd>: scroll to top

docs/keybindings/Keybindings_nl.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
## Dependencies Panel
1616

1717
<pre>
18-
<kbd>i</kbd>: [33m`npm install`[0m dependency
18+
<kbd>i</kbd>: install dependency
1919
<kbd>o</kbd>: open package.json
20-
<kbd>u</kbd>: [33m`npm update`[0m dependency
20+
<kbd>u</kbd>: update dependency
2121
<kbd>d</kbd>: `npm uninstall` dependency
2222
<kbd>t</kbd>: change dependency type (prod/dev/optional)
23-
<kbd>n</kbd>: [33m`npm install`[0m new dependency
23+
<kbd>n</kbd>: install new dependency
2424
<kbd>e</kbd>: edit dependency constraint
2525
<kbd>,</kbd>: previous page
2626
<kbd>.</kbd>: next page
@@ -45,12 +45,12 @@
4545

4646
<pre>
4747
<kbd>n</kbd>: add package to list
48-
<kbd>p</kbd>: [33m`npm pack`[0m package
49-
<kbd>l</kbd>: [33m`npm link <package>`[0m (or unlink if already linked)
50-
<kbd>L</kbd>: [33m`npm link`[0m (i.e. globally link) (or unlink if already linked)
48+
<kbd>p</kbd>: pack package
49+
<kbd>l</kbd>: link package (or unlink if already linked)
50+
<kbd>L</kbd>: globally link package (or unlink if already linked)
5151
<kbd>d</kbd>: remove package from list
52-
<kbd>i</kbd>: [33m`npm install`[0m package
53-
<kbd>b</kbd>: [33m`npm run build`[0m package
52+
<kbd>i</kbd>: install package dependencies
53+
<kbd>b</kbd>: build package
5454
<kbd>o</kbd>: open package.json
5555
<kbd>,</kbd>: previous page
5656
<kbd>.</kbd>: next page
@@ -62,7 +62,7 @@
6262
## Scripts Panel
6363

6464
<pre>
65-
<kbd>space</kbd>: [33m`npm run`[0m script
65+
<kbd>space</kbd>: run script
6666
<kbd>d</kbd>: remove script from package.json
6767
<kbd>e</kbd>: edit script
6868
<kbd>n</kbd>: add script
@@ -85,8 +85,8 @@
8585

8686
<pre>
8787
<kbd>d</kbd>: delete tarball
88-
<kbd>i</kbd>: [33m`npm install`[0m tarball
89-
<kbd>P</kbd>: [33m`npm publish`[0m tarball
88+
<kbd>i</kbd>: install tarball
89+
<kbd>P</kbd>: publish tarball
9090
<kbd>,</kbd>: previous page
9191
<kbd>.</kbd>: next page
9292
<kbd><</kbd>: scroll to top

docs/keybindings/Keybindings_pl.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
## Dependencies Panel
1616

1717
<pre>
18-
<kbd>i</kbd>: [33m`npm install`[0m dependency
18+
<kbd>i</kbd>: install dependency
1919
<kbd>o</kbd>: open package.json
20-
<kbd>u</kbd>: [33m`npm update`[0m dependency
20+
<kbd>u</kbd>: update dependency
2121
<kbd>d</kbd>: `npm uninstall` dependency
2222
<kbd>t</kbd>: change dependency type (prod/dev/optional)
23-
<kbd>n</kbd>: [33m`npm install`[0m new dependency
23+
<kbd>n</kbd>: install new dependency
2424
<kbd>e</kbd>: edit dependency constraint
2525
<kbd>,</kbd>: previous page
2626
<kbd>.</kbd>: next page
@@ -45,12 +45,12 @@
4545

4646
<pre>
4747
<kbd>n</kbd>: add package to list
48-
<kbd>p</kbd>: [33m`npm pack`[0m package
49-
<kbd>l</kbd>: [33m`npm link <package>`[0m (or unlink if already linked)
50-
<kbd>L</kbd>: [33m`npm link`[0m (i.e. globally link) (or unlink if already linked)
48+
<kbd>p</kbd>: pack package
49+
<kbd>l</kbd>: link package (or unlink if already linked)
50+
<kbd>L</kbd>: globally link package (or unlink if already linked)
5151
<kbd>d</kbd>: remove package from list
52-
<kbd>i</kbd>: [33m`npm install`[0m package
53-
<kbd>b</kbd>: [33m`npm run build`[0m package
52+
<kbd>i</kbd>: install package dependencies
53+
<kbd>b</kbd>: build package
5454
<kbd>o</kbd>: open package.json
5555
<kbd>,</kbd>: previous page
5656
<kbd>.</kbd>: next page
@@ -62,7 +62,7 @@
6262
## Scripts Panel
6363

6464
<pre>
65-
<kbd>space</kbd>: [33m`npm run`[0m script
65+
<kbd>space</kbd>: run script
6666
<kbd>d</kbd>: remove script from package.json
6767
<kbd>e</kbd>: edit script
6868
<kbd>n</kbd>: add script
@@ -85,8 +85,8 @@
8585

8686
<pre>
8787
<kbd>d</kbd>: delete tarball
88-
<kbd>i</kbd>: [33m`npm install`[0m tarball
89-
<kbd>P</kbd>: [33m`npm publish`[0m tarball
88+
<kbd>i</kbd>: install tarball
89+
<kbd>P</kbd>: publish tarball
9090
<kbd>,</kbd>: previous page
9191
<kbd>.</kbd>: next page
9292
<kbd><</kbd>: scroll to top
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package pm
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestAlternativeManagersBuildManagerSpecificCommands(t *testing.T) {
10+
project := NewProjectRef("/workspace/app")
11+
tests := []struct {
12+
name string
13+
manager PackageManager
14+
build func(PackageManager) CommandSpec
15+
want string
16+
}{
17+
{name: "pnpm install", manager: NewPNPM(), build: func(manager PackageManager) CommandSpec { return manager.Install(project) }, want: "pnpm install"},
18+
{name: "pnpm dev dependency", manager: NewPNPM(), build: func(manager PackageManager) CommandSpec { return manager.AddDev(project, NewDependencySpec("tsx")) }, want: "pnpm add --save-dev tsx"},
19+
{name: "pnpm optional dependency", manager: NewPNPM(), build: func(manager PackageManager) CommandSpec {
20+
return manager.AddOptional(project, NewDependencySpec("fsevents"))
21+
}, want: "pnpm add --save-optional fsevents"},
22+
{name: "modern yarn update", manager: NewYarn(), build: func(manager PackageManager) CommandSpec { return manager.Update(project, NewPackageName("react")) }, want: "yarn up react"},
23+
{name: "classic yarn update", manager: NewYarnClassic(), build: func(manager PackageManager) CommandSpec { return manager.Update(project, NewPackageName("react")) }, want: "yarn upgrade react"},
24+
{name: "modern yarn publish", manager: NewYarn(), build: func(manager PackageManager) CommandSpec { return manager.Publish(project, PublishOptions{}) }, want: "yarn npm publish"},
25+
}
26+
27+
for _, tt := range tests {
28+
t.Run(tt.name, func(t *testing.T) {
29+
spec := tt.build(tt.manager)
30+
assert.Equal(t, tt.want, spec.Preview)
31+
assert.Equal(t, project.Dir(), spec.Dir)
32+
})
33+
}
34+
}

internal/pm/detection.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,29 +84,29 @@ type packageMetadata struct {
8484
}
8585

8686
func DetectPackageManager(request DetectionRequest) DetectionResult {
87-
if result, ok := detectOverride(request.CLIOverride, DetectionSourceCLIOverride); ok {
87+
signals := detectProjectSignals(request.Project)
88+
if result, ok := detectOverride(request.CLIOverride, DetectionSourceCLIOverride, signals); ok {
8889
return result
8990
}
90-
if result, ok := detectOverride(request.EnvOverride, DetectionSourceEnvOverride); ok {
91+
if result, ok := detectOverride(request.EnvOverride, DetectionSourceEnvOverride, signals); ok {
9192
return result
9293
}
93-
if result, ok := detectOverride(request.ConfigOverride, DetectionSourceConfigOverride); ok {
94+
if result, ok := detectOverride(request.ConfigOverride, DetectionSourceConfigOverride, signals); ok {
9495
return result
9596
}
9697

97-
signals := detectProjectSignals(request.Project)
9898
return resultFromSignals(signals)
9999
}
100100

101-
func detectOverride(raw string, source DetectionSource) (DetectionResult, bool) {
101+
func detectOverride(raw string, source DetectionSource, signals []DetectionSignal) (DetectionResult, bool) {
102102
id, ok := parseManagerID(raw)
103103
if id == "" {
104104
return DetectionResult{}, false
105105
}
106106
if !ok {
107107
return invalidResult(id, source), true
108108
}
109-
return resultForManager(id, source, nil), true
109+
return resultForManager(id, source, signals), true
110110
}
111111

112112
func detectProjectSignals(project ProjectRef) []DetectionSignal {
@@ -183,14 +183,23 @@ func ambiguousSignals(signals []DetectionSignal) bool {
183183
}
184184

185185
func resultForManager(id ManagerID, source DetectionSource, signals []DetectionSignal) DetectionResult {
186-
if id == ManagerIDNPM {
186+
var manager PackageManager
187+
switch id {
188+
case ManagerIDNPM:
189+
manager = NewNPM()
190+
case ManagerIDPNPM:
191+
manager = NewPNPM()
192+
case ManagerIDYarn:
193+
manager = yarnManagerForSignals(signals)
194+
}
195+
if manager != nil {
187196
return DetectionResult{
188-
ID: ManagerIDNPM,
197+
ID: id,
189198
Source: source,
190199
Supported: true,
191200
Executable: true,
192201
Signals: signals,
193-
Manager: NewNPM(),
202+
Manager: manager,
194203
}
195204
}
196205
return DetectionResult{
@@ -207,6 +216,15 @@ func resultForManager(id ManagerID, source DetectionSource, signals []DetectionS
207216
}
208217
}
209218

219+
func yarnManagerForSignals(signals []DetectionSignal) PackageManager {
220+
for _, signal := range signals {
221+
if signal.Path == ".yarnrc.yml" || (strings.HasPrefix(strings.ToLower(signal.Value), "yarn@") && !strings.HasPrefix(strings.ToLower(signal.Value), "yarn@1.")) {
222+
return NewYarn()
223+
}
224+
}
225+
return NewYarnClassic()
226+
}
227+
210228
func invalidResult(id ManagerID, source DetectionSource) DetectionResult {
211229
return DetectionResult{
212230
ID: id,

0 commit comments

Comments
 (0)