Skip to content

Commit a8b7970

Browse files
committed
refactor
1 parent bfe349d commit a8b7970

3 files changed

Lines changed: 63 additions & 64 deletions

File tree

javascript/ql/lib/semmle/javascript/TSConfig.qll

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
private import javascript
6+
private import semmle.javascript.internal.paths.PathMapping
67

78
/**
89
* A TypeScript configuration file, usually named `tsconfig.json`.
@@ -134,3 +135,44 @@ private module ResolverConfig implements Folder::ResolveSig {
134135
}
135136

136137
private module Resolver = Folder::Resolve<ResolverConfig>;
138+
139+
/**
140+
* Gets a tsconfig file to use as fallback for handling paths in `c`.
141+
*
142+
* This holds for files and folders where no tsconfig seems to include it,
143+
* but it has one or more tsconfig files in parent directories.
144+
*/
145+
private TSConfig getFallbackTSConfig(Container c) {
146+
not c = any(TSConfig t).getAnIncludedContainer() and
147+
(
148+
c = result.getFolder()
149+
or
150+
result = getFallbackTSConfig(c.getParentContainer())
151+
)
152+
}
153+
154+
private class TSConfigPathMapping extends PathMapping, TSConfig {
155+
override File getAnAffectedFile() {
156+
result = this.getAnIncludedContainer()
157+
or
158+
this = getFallbackTSConfig(result)
159+
}
160+
161+
override predicate hasExactPathMapping(string pattern, Container newContext, string newPath) {
162+
exists(TSConfig tsconfig |
163+
tsconfig = this.getExtendedTSConfig*() and
164+
tsconfig.hasExactPathMapping(pattern, newPath) and
165+
newContext = tsconfig.getBaseUrlFolderOrOwnFolder()
166+
)
167+
}
168+
169+
override predicate hasPrefixPathMapping(string pattern, Container newContext, string newPath) {
170+
exists(TSConfig tsconfig |
171+
tsconfig = this.getExtendedTSConfig*() and
172+
tsconfig.hasPrefixPathMapping(pattern, newPath) and
173+
newContext = tsconfig.getBaseUrlFolderOrOwnFolder()
174+
)
175+
}
176+
177+
override predicate hasBaseUrl(Container base) { base = this.getBaseUrlFolder() }
178+
}

javascript/ql/lib/semmle/javascript/internal/paths/PathExprResolver.qll

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ private import semmle.javascript.internal.paths.PathMapping
55
private import semmle.javascript.internal.paths.PathConcatenation
66
private import semmle.javascript.dataflow.internal.DataFlowNode
77

8+
/**
9+
* Gets the file to import when an imported path resolves to the given `folder`.
10+
*/
811
File getFileFromFolderImport(Folder folder) {
912
result = folder.getJavaScriptFileOrTypings("index")
1013
or
@@ -23,7 +26,7 @@ private Variable filenameVar() { result.getName() = "__filename" }
2326
private signature predicate exprSig(Expr e);
2427

2528
module ResolveExpr<exprSig/1 shouldResolveExpr> {
26-
/** Holds if we need the constant-value of `node`. */
29+
/** Holds if we need the constant string-value of `node`. */
2730
private predicate needsConstantFolding(EarlyStageNode node) {
2831
exists(Expr e |
2932
shouldResolveExpr(e) and
@@ -78,23 +81,18 @@ module ResolveExpr<exprSig/1 shouldResolveExpr> {
7881
RelevantExpr() { shouldResolveExpr(this) }
7982

8083
string getValue() { result = getValue(TValueNode(this)) }
81-
}
8284

83-
/**
84-
* Gets a path mapping relevant for resolving `expr`.
85-
*/
86-
pragma[nomagic]
87-
private PathMapping getAPathMappingFromPathExpr(RelevantExpr expr) {
88-
result.getAnAffectedFile() = expr.getFile()
89-
}
90-
91-
/**
92-
* Gets the NPM package name from the beginning of the given import path, e.g.
93-
* gets `foo` from `foo/bar`, and `@example/foo` from `@example/foo/bar`.
94-
*/
95-
pragma[nomagic]
96-
private string getPackagePrefixFromPathExpr(RelevantExpr expr) {
97-
result = expr.getValue().(FilePath).getPackagePrefix()
85+
/**
86+
* Gets a path mapping relevant for resolving `expr`.
87+
*/
88+
pragma[nomagic]
89+
PathMapping getAPathMapping() { result.getAnAffectedFile() = this.getFile() }
90+
91+
/**
92+
* Gets the NPM package name from the beginning of the given import path.
93+
*/
94+
pragma[nomagic]
95+
string getPackagePrefix() { result = this.getValue().(FilePath).getPackagePrefix() }
9896
}
9997

10098
/**
@@ -104,7 +102,7 @@ module ResolveExpr<exprSig/1 shouldResolveExpr> {
104102
private predicate resolveViaPathMapping(RelevantExpr expr, Container base, string newPath) {
105103
// Handle path mappings such as `{ "paths": { "@/*": "./src/*" }}` in a tsconfig.json file
106104
exists(PathMapping mapping, string value |
107-
mapping = getAPathMappingFromPathExpr(expr) and
105+
mapping = expr.getAPathMapping() and
108106
value = expr.getValue()
109107
|
110108
mapping.hasExactPathMapping(value, base, newPath)
@@ -123,7 +121,7 @@ module ResolveExpr<exprSig/1 shouldResolveExpr> {
123121
// This part only handles the "exports" property of package.json. "main" and "modules" are
124122
// handled further down because their semantics are easier to handle there.
125123
exists(PackageJsonEx pkg, string packageName, string remainder |
126-
packageName = getPackagePrefixFromPathExpr(expr) and
124+
packageName = expr.getPackagePrefix() and
127125
pkg.getDeclaredPackageName() = packageName and
128126
remainder = expr.getValue().suffix(packageName.length()).regexpReplaceAll("^[/\\\\]", "")
129127
|
@@ -173,14 +171,14 @@ module ResolveExpr<exprSig/1 shouldResolveExpr> {
173171
// Resolve from baseUrl of relevant tsconfig.json file
174172
path = expr.getValue() and
175173
not path.isDotRelativePath() and
176-
getAPathMappingFromPathExpr(expr).hasBaseUrl(base)
174+
expr.getAPathMapping().hasBaseUrl(base)
177175
or
178176
// If the path starts with the name of a package, but did not match any path mapping,
179177
// resolve relative to the enclosing directory of that package.
180178
// Note that `getFileFromFolderImport` may subsequently redirect this to the package's "main",
181179
// so we don't have to deal with that here.
182180
exists(PackageJson pkg, string packageName |
183-
packageName = getPackagePrefixFromPathExpr(expr) and
181+
packageName = expr.getPackagePrefix() and
184182
pkg.getDeclaredPackageName() = packageName and
185183
path = expr.getValue().suffix(packageName.length()).regexpReplaceAll("^[/\\\\]", "") and
186184
base = pkg.getFolder()
@@ -219,7 +217,7 @@ module ResolveExpr<exprSig/1 shouldResolveExpr> {
219217
query PathExprToDebug pathExprs() { any() }
220218

221219
query string getPackagePrefixFromPathExpr_(PathExprToDebug expr) {
222-
result = getPackagePrefixFromPathExpr(expr)
220+
result = expr.getPackagePrefix()
223221
}
224222

225223
query predicate resolveViaPathMapping_(PathExprToDebug expr, Container base, string newPath) {

javascript/ql/lib/semmle/javascript/internal/paths/PathMapping.qll

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ private import javascript
66
private import semmle.javascript.TSConfig
77

88
/**
9-
* A configuration entity, such as a `tsconfig.json` file, which may provide path mappings.
9+
* A `tsconfig.json`-like configuration object that can affect import resolution via path mappings.
1010
*/
1111
abstract class PathMapping extends Locatable {
1212
/**
@@ -29,44 +29,3 @@ abstract class PathMapping extends Locatable {
2929
/** Holds if non-relative paths in affected files should be resolved relative to `base`. */
3030
predicate hasBaseUrl(Container base) { none() }
3131
}
32-
33-
/**
34-
* Gets a tsconfig file to use as fallback for handling paths in `c`.
35-
*
36-
* This holds for files and folders where no tsconfig seems to include it,
37-
* but it has one or more tsconfig files in parent directories.
38-
*/
39-
private TSConfig getFallbackTSConfig(Container c) {
40-
not c = any(TSConfig t).getAnIncludedContainer() and
41-
(
42-
c = result.getFolder()
43-
or
44-
result = getFallbackTSConfig(c.getParentContainer())
45-
)
46-
}
47-
48-
private class TSConfigPathMapping extends PathMapping, TSConfig {
49-
override File getAnAffectedFile() {
50-
result = this.getAnIncludedContainer()
51-
or
52-
this = getFallbackTSConfig(result)
53-
}
54-
55-
override predicate hasExactPathMapping(string pattern, Container newContext, string newPath) {
56-
exists(TSConfig tsconfig |
57-
tsconfig = this.getExtendedTSConfig*() and
58-
tsconfig.hasExactPathMapping(pattern, newPath) and
59-
newContext = tsconfig.getBaseUrlFolderOrOwnFolder()
60-
)
61-
}
62-
63-
override predicate hasPrefixPathMapping(string pattern, Container newContext, string newPath) {
64-
exists(TSConfig tsconfig |
65-
tsconfig = this.getExtendedTSConfig*() and
66-
tsconfig.hasPrefixPathMapping(pattern, newPath) and
67-
newContext = tsconfig.getBaseUrlFolderOrOwnFolder()
68-
)
69-
}
70-
71-
override predicate hasBaseUrl(Container base) { base = this.getBaseUrlFolder() }
72-
}

0 commit comments

Comments
 (0)