Skip to content

Commit 349331d

Browse files
authored
Merge pull request #10082 from asgerf/js/exports-handling2
JS: Handle nested conditions in "exports" section
2 parents a46e2b3 + 449e697 commit 349331d

File tree

2 files changed

+30
-15
lines changed

2 files changed

+30
-15
lines changed

javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,30 +147,22 @@ private string getASrcFolderName() { result = ["ts", "js", "src", "lib"] }
147147
*/
148148
class MainModulePath extends PathExpr, @json_string {
149149
PackageJson pkg;
150-
string relativePath;
151150

152151
MainModulePath() {
153-
relativePath = "." and
154152
this = pkg.getPropValue(["main", "module"])
155153
or
156-
// { "exports": "path" } is sugar for { "exports": { ".": "path" }}
157-
relativePath = "." and
158-
this = pkg.getPropValue("exports")
159-
or
160-
exists(JsonValue val | val = pkg.getPropValue("exports").getPropValue(relativePath) |
161-
// Either specified directly as a string: { "./path": "./path.js" }
162-
this = val
163-
or
164-
// Or by module type: { "./path": { "require": "./path.cjs", ... }}
165-
this = val.getPropValue(_)
166-
)
154+
this = getAPartOfExportsSection(pkg)
167155
}
168156

169157
/** Gets the `package.json` file in which this path occurs. */
170158
PackageJson getPackageJson() { result = pkg }
171159

172160
/** Gets the relative path under which this is exported, usually starting with a `.`. */
173-
string getRelativePath() { result = relativePath }
161+
string getRelativePath() {
162+
result = getExportRelativePath(this)
163+
or
164+
not exists(getExportRelativePath(this)) and result = "."
165+
}
174166

175167
/** DEPRECATED: Alias for getPackageJson */
176168
deprecated PackageJSON getPackageJSON() { result = getPackageJson() }
@@ -183,6 +175,29 @@ class MainModulePath extends PathExpr, @json_string {
183175
}
184176
}
185177

178+
private JsonValue getAPartOfExportsSection(PackageJson pkg) {
179+
result = pkg.getPropValue("exports")
180+
or
181+
result = getAPartOfExportsSection(pkg).getPropValue(_)
182+
}
183+
184+
/** Gets the text of one of the conditions or paths enclosing the given `part` of an `exports` section. */
185+
private string getAnEnclosingExportProperty(JsonValue part) {
186+
exists(JsonObject parent, string prop |
187+
parent = getAPartOfExportsSection(_) and
188+
part = parent.getPropValue(prop)
189+
|
190+
result = prop
191+
or
192+
result = getAnEnclosingExportProperty(parent)
193+
)
194+
}
195+
196+
private string getExportRelativePath(JsonValue part) {
197+
result = getAnEnclosingExportProperty(part) and
198+
result.matches(".%")
199+
}
200+
186201
module MainModulePath {
187202
/** Gets the path to the main entry point of `pkg`. */
188203
MainModulePath of(PackageJson pkg) { result = of(pkg, ".") }

javascript/ql/test/library-tests/NPM/src/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
"peerDependencies": {
1818
"tea": "2.x"
1919
}
20-
}
20+
}

0 commit comments

Comments
 (0)