Skip to content

Commit dcfaa4d

Browse files
authored
Merge pull request #485 from github/npm-workspaces
Initial support for npm workspaces
2 parents c3e82b2 + eaa674d commit dcfaa4d

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

docs/sources/npm.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@
22

33
The npm source will detect dependencies `package.json` is found at an apps `source_path`. It uses `npm list` to enumerate dependencies and metadata.
44

5-
### Including development dependencies
5+
## Including development dependencies
66

77
By default, the npm source will exclude all development dependencies. To include development or test dependencies, set `production_only: false` in the licensed configuration.
88

99
```yml
1010
npm:
1111
production_only: false
1212
```
13+
14+
## Using licensed with npm workspaces
15+
16+
Licensed requires npm version 8.5.0 or later to enumerate dependencies inside of npm workspaces. For the best results, treat each workspace directory as a separate app `source_path`:
17+
18+
```yml
19+
apps:
20+
- source_path: path/to/workspace/a
21+
- source_path: path/to/workspace/b
22+
```

lib/licensed/sources/npm.rb

+23-1
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ def license_metadata
2424
end
2525

2626
def enabled?
27-
Licensed::Shell.tool_available?("npm") && File.exist?(config.pwd.join("package.json"))
27+
Licensed::Shell.tool_available?("npm") && File.exist?(package_json_path)
2828
end
2929

3030
def enumerate_dependencies
3131
packages.map do |name, package|
32+
next if package["name"] == project_name
33+
3234
errors = package["problems"] unless package["path"]
3335
Dependency.new(
3436
name: name,
@@ -159,6 +161,26 @@ def peer_dependency(parent, name)
159161
def extract_version(parent, name)
160162
parent&.dig("_dependencies", name) || peer_dependency(parent, name)
161163
end
164+
165+
# Returns the current projects name
166+
def project_name
167+
return unless package_json
168+
package_json["name"]
169+
end
170+
171+
## Returns the parse package.json for the current project
172+
def package_json
173+
return unless File.exist?(package_json_path)
174+
175+
@package_json ||= JSON.parse(File.read(package_json_path))
176+
rescue JSON::ParserError => e
177+
message = "Licensed was unable to parse package.json. JSON Error: #{e.message}"
178+
raise Licensed::Sources::Source::Error, message
179+
end
180+
181+
def package_json_path
182+
@package_json_path ||= File.join(config.pwd, "package.json")
183+
end
162184
end
163185
end
164186
end

test/fixtures/npm/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "fixtures",
2+
"name": "licensed-fixtures",
33
"version": "1.0.0",
44
"dependencies": {
55
"@github/query-selector": "1.0.3",
@@ -11,6 +11,9 @@
1111
"devDependencies": {
1212
"string.prototype.startswith": "0.2.0"
1313
},
14+
"workspaces": [
15+
"packages/a"
16+
],
1417
"description": "npm test fixture",
1518
"repository": "https://github.com/github/licensed",
1619
"license": "MIT"
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "licensed-fixtures-a",
3+
"version": "1.0.0",
4+
"description": "",
5+
"author": "",
6+
"license": "MIT",
7+
"dependencies": {
8+
"callbackify": "1.1.0"
9+
}
10+
}

test/sources/npm_test.rb

+25
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,31 @@
135135
end
136136
end
137137
end
138+
139+
describe "from a workspace" do
140+
let(:fixtures) { File.expand_path("../../fixtures/npm/packages/a", __FILE__) }
141+
142+
it "finds dependencies" do
143+
# workspaces will only work as expected with npm > 8.5.0
144+
skip if source.npm_version < Gem::Version.new("8.5.0")
145+
146+
Dir.chdir fixtures do
147+
dep = source.dependencies.detect { |d| d.name == "callbackify" }
148+
assert dep
149+
assert_equal "npm", dep.record["type"]
150+
assert_equal "1.1.0", dep.version
151+
end
152+
end
153+
154+
it "does not include the current workspace project" do
155+
# workspaces will only work as expected with npm > 8.5.0
156+
skip if source.npm_version < Gem::Version.new("8.5.0")
157+
158+
Dir.chdir fixtures do
159+
refute source.dependencies.detect { |d| d.name == "licensed-fixtures-a" }
160+
end
161+
end
162+
end
138163
end
139164

140165
describe "missing dependencies (glob is missing package)" do

0 commit comments

Comments
 (0)