Skip to content

Commit b446a00

Browse files
committed
JS: Add internal extension of PackageJson class
1 parent 6db5781 commit b446a00

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
private import javascript
2+
private import semmle.javascript.internal.paths.JSPaths
3+
4+
/**
5+
* Extension of `PackageJson` with some internal path-resolution predicates.
6+
*/
7+
class PackageJsonEx extends PackageJson {
8+
private JsonValue getAPartOfExportsSection(string pattern) {
9+
result = this.getPropValue("exports") and
10+
pattern = ""
11+
or
12+
exists(string prop, string prevPath |
13+
result = this.getAPartOfExportsSection(prevPath).getPropValue(prop) and
14+
if prop.matches("./%") then pattern = prop.suffix(2) else pattern = prevPath
15+
)
16+
}
17+
18+
predicate hasPathMapping(string pattern, string newPath) {
19+
this.getAPartOfExportsSection(pattern).getStringValue() = newPath
20+
}
21+
22+
predicate hasExactPathMapping(string pattern, string newPath) {
23+
this.getAPartOfExportsSection(pattern).getStringValue() = newPath and
24+
not pattern.matches("%*%")
25+
}
26+
27+
predicate hasPrefixPathMapping(string pattern, string newPath) {
28+
this.hasPathMapping(pattern + "*", newPath + "*")
29+
}
30+
31+
predicate hasExactPathMappingTo(string pattern, Container target) {
32+
exists(string newPath |
33+
this.hasExactPathMapping(pattern, newPath) and
34+
target = Resolver::resolve(this.getFolder(), newPath)
35+
)
36+
}
37+
38+
predicate hasPrefixPathMappingTo(string pattern, Container target) {
39+
exists(string newPath |
40+
this.hasPrefixPathMapping(pattern, newPath) and
41+
target = Resolver::resolve(this.getFolder(), newPath)
42+
)
43+
}
44+
45+
string getMainPath() { result = this.getPropStringValue(["main", "module"]) }
46+
47+
File getMainFile() {
48+
exists(Container main | main = Resolver::resolve(this.getFolder(), this.getMainPath()) |
49+
result = main
50+
or
51+
result = main.(Folder).getJavaScriptFileOrTypings("index")
52+
)
53+
}
54+
55+
string getAPathInFilesArray() {
56+
result = this.getPropValue("files").(JsonArray).getElementStringValue(_)
57+
}
58+
59+
Container getAFileInFilesArray() {
60+
result = Resolver::resolve(this.getFolder(), this.getAPathInFilesArray())
61+
}
62+
}
63+
64+
private module ResolverConfig implements Folder::ResolveSig {
65+
additional predicate shouldResolve(PackageJsonEx pkg, Container base, string path) {
66+
base = pkg.getFolder() and
67+
(
68+
pkg.hasExactPathMapping(_, path)
69+
or
70+
pkg.hasPrefixPathMapping(_, path)
71+
or
72+
path = pkg.getMainPath()
73+
or
74+
path = pkg.getAPathInFilesArray()
75+
)
76+
}
77+
78+
predicate shouldResolve(Container base, string path) { shouldResolve(_, base, path) }
79+
80+
predicate getAnAdditionalChild = JSPaths::getAnAdditionalChild/2;
81+
82+
predicate isOptionalPathComponent(string segment) { segment = ["cjs", "mjs", "js"] }
83+
}
84+
85+
private module Resolver = Folder::Resolve<ResolverConfig>;

0 commit comments

Comments
 (0)