mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
@@ -235,6 +235,9 @@ class Require extends CallExpr, Import {
|
||||
|
||||
override Module resolveImportedPath() {
|
||||
moduleInFile(result, load(min(int prio | moduleInFile(_, load(prio)))))
|
||||
or
|
||||
not exists(Module mod | moduleInFile(mod, load(_))) and
|
||||
result = Import.super.resolveImportedPath()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,26 +144,24 @@ abstract class PathString extends string {
|
||||
Path resolveUpTo(int n, Folder root) {
|
||||
n = 0 and result.getContainer() = root and root = getARootFolder()
|
||||
or
|
||||
exists(Path base | base = resolveUpTo(n - 1, root) |
|
||||
exists(string next | next = getComponent(n - 1) |
|
||||
// handle empty components and the special "." folder
|
||||
(next = "" or next = ".") and
|
||||
result = base
|
||||
or
|
||||
// handle the special ".." folder
|
||||
next = ".." and result = base.(ConsPath).getParent()
|
||||
or
|
||||
// special handling for Windows drive letters when resolving absolute path:
|
||||
// the extractor populates "C:/" as a folder that has path "C:/" but name ""
|
||||
n = 1 and
|
||||
next.regexpMatch("[A-Za-z]:") and
|
||||
root.getBaseName() = "" and
|
||||
root.toString() = next.toUpperCase() + "/" and
|
||||
result = base
|
||||
or
|
||||
// default case
|
||||
result = TConsPath(base, next)
|
||||
)
|
||||
exists(Path base, string next | next = getComponent(this, n - 1, base, root) |
|
||||
// handle empty components and the special "." folder
|
||||
(next = "" or next = ".") and
|
||||
result = base
|
||||
or
|
||||
// handle the special ".." folder
|
||||
next = ".." and result = base.(ConsPath).getParent()
|
||||
or
|
||||
// special handling for Windows drive letters when resolving absolute path:
|
||||
// the extractor populates "C:/" as a folder that has path "C:/" but name ""
|
||||
n = 1 and
|
||||
next.regexpMatch("[A-Za-z]:") and
|
||||
root.getBaseName() = "" and
|
||||
root.toString() = next.toUpperCase() + "/" and
|
||||
result = base
|
||||
or
|
||||
// default case
|
||||
result = TConsPath(base, next)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -174,6 +172,105 @@ abstract class PathString extends string {
|
||||
Path resolve(Folder root) { result = resolveUpTo(getNumComponent(), root) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th component of the path `str`, where `base` is the resolved path one level up.
|
||||
* Supports that the root directory might be compiled output from TypeScript.
|
||||
*/
|
||||
private string getComponent(PathString str, int n, Path base, Folder root) {
|
||||
base = str.resolveUpTo(n, root) and
|
||||
(
|
||||
result = str.getComponent(n)
|
||||
or
|
||||
result = TypeScriptOutDir::getOriginalTypeScriptFolder(str.getComponent(n), base.getContainer())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicates for resolving imports to compiled TypeScript.
|
||||
*/
|
||||
private module TypeScriptOutDir {
|
||||
/**
|
||||
* Gets a folder of TypeScript files that is compiled to JavaScript files in `outdir` relative to a `parent`.
|
||||
*/
|
||||
string getOriginalTypeScriptFolder(string outdir, Folder parent) {
|
||||
exists(JSONObject tsconfig |
|
||||
tsconfig.getFile().getBaseName() = "tsconfig.json" and
|
||||
tsconfig.isTopLevel() and
|
||||
tsconfig.getFile().getParentContainer() = parent
|
||||
|
|
||||
outdir =
|
||||
tsconfig
|
||||
.getPropValue("compilerOptions")
|
||||
.(JSONObject)
|
||||
.getPropValue("outDir")
|
||||
.(JSONString)
|
||||
.getValue() and
|
||||
result = getEffectiveRootDirFromTSConfig(tsconfig)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the directory that contains the TypeScript source files.
|
||||
* Based on the tsconfig.json file `tsconfig`.
|
||||
*/
|
||||
pragma[inline]
|
||||
private string getEffectiveRootDirFromTSConfig(JSONObject tsconfig) {
|
||||
// if an explicit "rootDir" option exists, then use that.
|
||||
result = getRootDir(tsconfig)
|
||||
or
|
||||
// otherwise, infer from "includes"
|
||||
not exists(getRootDir(tsconfig)) and
|
||||
(
|
||||
// if unique root folder in "includes", then use that.
|
||||
result = unique( | | getARootDirFromInclude(tsconfig))
|
||||
or
|
||||
// otherwise use "." if the includes are split over multiple folders.
|
||||
exists(getARootDirFromInclude(tsconfig)) and
|
||||
not exists(unique( | | getARootDirFromInclude(tsconfig))) and
|
||||
result = "."
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first folder from `path`.
|
||||
*/
|
||||
bindingset[path]
|
||||
private string getRootFolderFromPath(string path) {
|
||||
not exists(path.indexOf("/")) and result = path
|
||||
or
|
||||
result = path.substring(0, path.indexOf("/", 0, 0))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a root directory containing TypeScript files based on the "include" option from tsconfig.json.
|
||||
* Can have multiple results if the includes are from multiple folders.
|
||||
*/
|
||||
pragma[inline]
|
||||
private string getARootDirFromInclude(JSONObject tsconfig) {
|
||||
result =
|
||||
getRootFolderFromPath(tsconfig
|
||||
.getPropValue("include")
|
||||
.(JSONArray)
|
||||
.getElementValue(_)
|
||||
.(JSONString)
|
||||
.getValue())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the "rootDir" option from a tsconfig.json.
|
||||
*/
|
||||
pragma[inline]
|
||||
private string getRootDir(JSONObject tsconfig) {
|
||||
result =
|
||||
tsconfig
|
||||
.getPropValue("compilerOptions")
|
||||
.(JSONObject)
|
||||
.getPropValue("rootDir")
|
||||
.(JSONString)
|
||||
.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression whose value represents a (relative or absolute) file system path.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
var foo1 = require('./lib/src/foo.js');
|
||||
var foo1 = require('./lib/src2/foo.js');
|
||||
var foo2 = require('./src/foo.ts');
|
||||
var foo2 = require('./src2/foo.ts');
|
||||
@@ -0,0 +1 @@
|
||||
export default class Foo {}
|
||||
@@ -0,0 +1 @@
|
||||
export default class Foo {}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src2/**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --include **/tsconfig.json
|
||||
@@ -0,0 +1,2 @@
|
||||
var foo1 = require('./lib/index.js');
|
||||
var foo2 = require('./src/index.ts');
|
||||
@@ -0,0 +1 @@
|
||||
export default class Foo {}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default class Foo {}
|
||||
@@ -0,0 +1,2 @@
|
||||
var foo1 = require('./lib/foo.js');
|
||||
var foo2 = require('./foo.ts');
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
var foo1 = require('./lib/index.js');
|
||||
var foo2 = require('./src/index.ts');
|
||||
|
||||
var foo3 = require('./lib/index');
|
||||
var foo4 = require('./src/index');
|
||||
@@ -0,0 +1 @@
|
||||
export default class Foo {}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
| nonUniqueInclude/index.js:1:12:1:38 | require ... oo.js') | nonUniqueInclude/src/foo.ts:1:1:1:27 | <toplevel> |
|
||||
| nonUniqueInclude/index.js:2:12:2:39 | require ... oo.js') | nonUniqueInclude/src2/foo.ts:1:1:1:27 | <toplevel> |
|
||||
| nonUniqueInclude/index.js:3:12:3:34 | require ... oo.ts') | nonUniqueInclude/src/foo.ts:1:1:1:27 | <toplevel> |
|
||||
| nonUniqueInclude/index.js:4:12:4:35 | require ... oo.ts') | nonUniqueInclude/src2/foo.ts:1:1:1:27 | <toplevel> |
|
||||
| rootDir/index.js:1:12:1:36 | require ... ex.js') | rootDir/src/index.ts:1:1:1:27 | <toplevel> |
|
||||
| rootDir/index.js:2:12:2:36 | require ... ex.ts') | rootDir/src/index.ts:1:1:1:27 | <toplevel> |
|
||||
| rootDirIsDot/index.js:1:12:1:34 | require ... oo.js') | rootDirIsDot/foo.ts:1:1:1:27 | <toplevel> |
|
||||
| rootDirIsDot/index.js:2:12:2:30 | require('./foo.ts') | rootDirIsDot/foo.ts:1:1:1:27 | <toplevel> |
|
||||
| simpleOutDir/index.js:1:12:1:36 | require ... ex.js') | simpleOutDir/src/index.ts:1:1:1:27 | <toplevel> |
|
||||
| simpleOutDir/index.js:2:12:2:36 | require ... ex.ts') | simpleOutDir/src/index.ts:1:1:1:27 | <toplevel> |
|
||||
| simpleOutDir/index.js:4:12:4:33 | require ... index') | simpleOutDir/src/index.ts:1:1:1:27 | <toplevel> |
|
||||
| simpleOutDir/index.js:5:12:5:33 | require ... index') | simpleOutDir/src/index.ts:1:1:1:27 | <toplevel> |
|
||||
@@ -0,0 +1,7 @@
|
||||
import javascript
|
||||
|
||||
query predicate resolveableImport(Import imp, Module mod) {
|
||||
mod = imp.getImportedModule() and
|
||||
not imp.getTopLevel().isExterns() and
|
||||
not mod.getTopLevel().isExterns()
|
||||
}
|
||||
Reference in New Issue
Block a user