Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
eb05996
Move getAChildContainer one scope up
asgerf Apr 24, 2025
2ce01bf
Add Folder::Resolve as a generalisation of Folder::Append
asgerf Apr 24, 2025
ec9d15b
JS: Make shared Folder module visible
asgerf Apr 24, 2025
8c0b0c4
JS: Ensure json files are extracted properly in tests
asgerf Apr 24, 2025
359525b
JS: Extract more tsconfig.json patterns
asgerf Apr 29, 2025
565cb43
JS: Add test
asgerf Apr 24, 2025
17aa522
JS: Add some helpers
asgerf Apr 24, 2025
ef32a03
JS: Extract from methods from PathString into a non-abstract base class
asgerf Apr 28, 2025
59e1cbc
JS: Add tsconfig class
asgerf Apr 24, 2025
bb91df8
JS: Add helper for doing path resolution with JS rules
asgerf Apr 24, 2025
f542956
JS: Add internal extension of PackageJson class
asgerf Apr 24, 2025
ed4864e
JS: Add two more helpers to FilePath class
asgerf Apr 28, 2025
6725cb5
JS: Implement import resolution
asgerf Apr 29, 2025
e4420f6
JS: Move babel-root-import test
asgerf Apr 28, 2025
d724874
JS: Implement babel-plugin-root-import as a PathMapping
asgerf Apr 28, 2025
a195d07
JS: Resolve Angular2 templateUrl with ResolveExpr instead of PathExpr
asgerf Apr 28, 2025
c293f03
JS: Remove a dependency on getImportedPath()
asgerf Apr 28, 2025
fe055ad
JS: Use PackageJsonEx instead of resolveMainModule
asgerf Apr 28, 2025
ed2a832
JS: Deprecate PathExpr and related classes
asgerf Apr 29, 2025
be5de9c
JS: Update test output
asgerf Apr 29, 2025
5de2c93
JS: Rename getTargetFile to getImportedFile and remove its deprecated…
asgerf Apr 29, 2025
70a5ec5
JS: Add package.json files in tests relying on node_modules
asgerf Apr 29, 2025
b0f73f1
JS: Update test output now that we import .d.ts files more liberally
asgerf Apr 29, 2025
f3e0cfd
Apply suggestions from code review
asgerf May 2, 2025
5c9218f
JS: Add comment about 'path' heuristic
asgerf May 2, 2025
1f308ee
JS: Explain use of monotonicAggregates
asgerf May 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion javascript/ql/examples/snippets/importfrom.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
import javascript

from ImportDeclaration id
where id.getImportedPath().getValue() = "react"
where id.getImportedPathString() = "react"
select id
2 changes: 1 addition & 1 deletion javascript/ql/lib/definitions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private predicate importLookup(AstNode path, Module target, string kind) {
kind = "I" and
(
exists(Import i |
path = i.getImportedPath() and
path = i.getImportedPathExpr() and
target = i.getImportedModule()
)
or
Expand Down
28 changes: 18 additions & 10 deletions javascript/ql/lib/semmle/javascript/AMD.qll
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,14 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
result = this.getArgument(1)
}

/** DEPRECATED. Use `getDependencyExpr` instead. */
deprecated PathExpr getDependency(int i) { result = this.getDependencyExpr(i) }

/** DEPRECATED. Use `getADependencyExpr` instead. */
deprecated PathExpr getADependency() { result = this.getADependencyExpr() }

/** Gets the `i`th dependency of this module definition. */
PathExpr getDependency(int i) {
Expr getDependencyExpr(int i) {
exists(Expr expr |
expr = this.getDependencies().getElement(i) and
not isPseudoDependency(expr.getStringValue()) and
Expand All @@ -71,8 +77,8 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
}

/** Gets a dependency of this module definition. */
PathExpr getADependency() {
result = this.getDependency(_) or
Expr getADependencyExpr() {
result = this.getDependencyExpr(_) or
result = this.getARequireCall().getAnArgument()
}

Expand Down Expand Up @@ -233,7 +239,7 @@ private class AmdDependencyPath extends PathExprCandidate {
}

/** A constant path element appearing in an AMD dependency expression. */
private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
deprecated private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() }

override string getValue() { result = this.getStringValue() }
Expand Down Expand Up @@ -261,11 +267,13 @@ private predicate amdModuleTopLevel(AmdModuleDefinition def, TopLevel tl) {
* An AMD dependency, viewed as an import.
*/
private class AmdDependencyImport extends Import {
AmdDependencyImport() { this = any(AmdModuleDefinition def).getADependency() }
AmdDependencyImport() { this = any(AmdModuleDefinition def).getADependencyExpr() }

override Module getEnclosingModule() { this = result.(AmdModule).getDefine().getADependency() }
override Module getEnclosingModule() {
this = result.(AmdModule).getDefine().getADependencyExpr()
}

override PathExpr getImportedPath() { result = this }
override Expr getImportedPathExpr() { result = this }

/**
* Gets a file that looks like it might be the target of this import.
Expand All @@ -274,7 +282,7 @@ private class AmdDependencyImport extends Import {
* adding well-known JavaScript file extensions like `.js`.
*/
private File guessTarget() {
exists(PathString imported, string abspath, string dirname, string basename |
exists(FilePath imported, string abspath, string dirname, string basename |
this.targetCandidate(result, abspath, imported, dirname, basename)
|
abspath.regexpMatch(".*/\\Q" + imported + "\\E")
Expand All @@ -296,9 +304,9 @@ private class AmdDependencyImport extends Import {
* `dirname` and `basename` to the dirname and basename (respectively) of `imported`.
*/
private predicate targetCandidate(
File f, string abspath, PathString imported, string dirname, string basename
File f, string abspath, FilePath imported, string dirname, string basename
) {
imported = this.getImportedPath().getValue() and
imported = this.getImportedPathString() and
f.getStem() = imported.getStem() and
f.getAbsolutePath() = abspath and
dirname = imported.getDirName() and
Expand Down
8 changes: 4 additions & 4 deletions javascript/ql/lib/semmle/javascript/ES2015Modules.qll
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ private predicate hasDefaultExport(ES2015Module mod) {
class ImportDeclaration extends Stmt, Import, @import_declaration {
override ES2015Module getEnclosingModule() { result = this.getTopLevel() }

override PathExpr getImportedPath() { result = this.getChildExpr(-1) }

/**
* INTERNAL USE ONLY. DO NOT USE.
*/
string getRawImportPath() { result = this.getChildExpr(-1).getStringValue() }

override Expr getImportedPathExpr() { result = this.getChildExpr(-1) }

/**
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
*
Expand Down Expand Up @@ -155,7 +155,7 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
}

/** A literal path expression appearing in an `import` declaration. */
private class LiteralImportPath extends PathExpr, ConstantString {
deprecated private class LiteralImportPath extends PathExpr, ConstantString {
LiteralImportPath() { exists(ImportDeclaration req | this = req.getChildExpr(-1)) }

override string getValue() { result = this.getStringValue() }
Expand Down Expand Up @@ -736,7 +736,7 @@ abstract class ReExportDeclaration extends ExportDeclaration {
}

/** A literal path expression appearing in a re-export declaration. */
private class LiteralReExportPath extends PathExpr, ConstantString {
deprecated private class LiteralReExportPath extends PathExpr, ConstantString {
LiteralReExportPath() { exists(ReExportDeclaration bred | this = bred.getImportedPath()) }

override string getValue() { result = this.getStringValue() }
Expand Down
4 changes: 2 additions & 2 deletions javascript/ql/lib/semmle/javascript/Expr.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2821,7 +2821,7 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
result = this.getSource().getFirstControlFlowNode()
}

override PathExpr getImportedPath() { result = this.getSource() }
override Expr getImportedPathExpr() { result = this.getSource() }

/**
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
Expand Down Expand Up @@ -2852,7 +2852,7 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
}

/** A literal path expression appearing in a dynamic import. */
private class LiteralDynamicImportPath extends PathExpr, ConstantString {
deprecated private class LiteralDynamicImportPath extends PathExpr, ConstantString {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Napalys.
Every 3 months I usually run a script to delete all deprecations that are past the deprecation period (a year).
I think that's something you can take over, I'll introduce you to it after the offsite.

LiteralDynamicImportPath() {
exists(DynamicImportExpr di | this.getParentExpr*() = di.getSource())
}
Expand Down
10 changes: 8 additions & 2 deletions javascript/ql/lib/semmle/javascript/HTML.qll
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ module HTML {
result = path.regexpCapture("file://(/.*)", 1)
or
not path.regexpMatch("(\\w+:)?//.*") and
result = this.getSourcePath().(ScriptSrcPath).resolve(this.getSearchRoot()).toString()
result = ResolveScriptSrc::resolve(this.getSearchRoot(), this.getSourcePath()).toString()
)
}

Expand Down Expand Up @@ -274,10 +274,16 @@ module HTML {
)
}

private module ResolverConfig implements Folder::ResolveSig {
predicate shouldResolve(Container base, string path) { scriptSrc(path, base) }
}

private module ResolveScriptSrc = Folder::Resolve<ResolverConfig>;

/**
* A path string arising from the `src` attribute of a `script` tag.
*/
private class ScriptSrcPath extends PathString {
deprecated private class ScriptSrcPath extends PathString {
ScriptSrcPath() { scriptSrc(this, _) }

override Folder getARootFolder() { scriptSrc(this, result) }
Expand Down
16 changes: 11 additions & 5 deletions javascript/ql/lib/semmle/javascript/Modules.qll
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ abstract class Module extends TopLevel {
* This predicate is not part of the public API, it is only exposed to allow
* overriding by subclasses.
*/
predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
deprecated predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
path.getEnclosingModule() = this and
priority = 0 and
exists(string v | v = path.getValue() |
Expand All @@ -90,7 +90,7 @@ abstract class Module extends TopLevel {
* resolves to a folder containing a main module (such as `index.js`), then
* that file is the result.
*/
File resolve(PathExpr path) {
deprecated File resolve(PathExpr path) {
path.getEnclosingModule() = this and
(
// handle the case where the import path is complete
Expand Down Expand Up @@ -123,8 +123,14 @@ abstract class Import extends AstNode {
/** Gets the module in which this import appears. */
abstract Module getEnclosingModule();

/** DEPRECATED. Use `getImportedPathExpr` instead. */
deprecated PathExpr getImportedPath() { result = this.getImportedPathExpr() }

/** Gets the (unresolved) path that this import refers to. */
abstract PathExpr getImportedPath();
abstract Expr getImportedPathExpr();

/** Gets the imported path as a string. */
final string getImportedPathString() { result = this.getImportedPathExpr().getStringValue() }

/**
* Gets an externs module the path of this import resolves to.
Expand All @@ -133,7 +139,7 @@ abstract class Import extends AstNode {
* path is assumed to be a possible target of the import.
*/
Module resolveExternsImport() {
result.isExterns() and result.getName() = this.getImportedPath().getValue()
result.isExterns() and result.getName() = this.getImportedPathString()
}

/**
Expand All @@ -144,7 +150,7 @@ abstract class Import extends AstNode {
/**
* Gets the module the path of this import resolves to.
*/
File getTargetFile() { result = ImportPathResolver::resolveExpr(this.getImportedPath()) }
File getTargetFile() { result = ImportPathResolver::resolveExpr(this.getImportedPathExpr()) }

/**
* DEPRECATED. Use `getImportedModule()` instead.
Expand Down
32 changes: 10 additions & 22 deletions javascript/ql/lib/semmle/javascript/NodeJS.qll
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class NodeModule extends Module {
)
}

override predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
deprecated override predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
path.getEnclosingModule() = this and
exists(string pathval | pathval = path.getValue() |
// paths starting with `./` or `../` are resolved relative to the importing
Expand Down Expand Up @@ -236,11 +236,6 @@ private class RequireVariable extends Variable {
}
}

/**
* Holds if module `m` is in file `f`.
*/
private predicate moduleInFile(Module m, File f) { m.getFile() = f }

private predicate isModuleModule(EarlyStageNode nd) {
exists(ImportDeclaration imp | imp.getRawImportPath() = "module" |
nd = TDestructuredModuleImportNode(imp)
Expand Down Expand Up @@ -328,24 +323,17 @@ private predicate isRequire(EarlyStageNode nd) {
class Require extends CallExpr, Import {
Require() { isRequire(TValueNode(this.getCallee())) }

override PathExpr getImportedPath() { result = this.getArgument(0) }
override Expr getImportedPathExpr() { result = this.getArgument(0) }

override Module getEnclosingModule() { this = result.getAnImport() }

override Module resolveImportedPath() {
moduleInFile(result, this.load(min(int prio | moduleInFile(_, this.load(prio)))))
or
not moduleInFile(_, this.load(_)) and
result = Import.super.resolveImportedPath()
}

/**
* Gets the file that is imported by this `require`.
*
* The result can be a JavaScript file, a JSON file or a `.node` file.
* Externs files are not treated differently from other files by this predicate.
*/
File getImportedFile() { result = this.load(min(int prio | exists(this.load(prio)))) }
deprecated File getImportedFile() { result = this.load(min(int prio | exists(this.load(prio)))) }

/**
* Gets the file that this `require` refers to (which may not be a JavaScript file),
Expand Down Expand Up @@ -402,8 +390,8 @@ class Require extends CallExpr, Import {
* predicate `tryExtensions` that handles the repeated distinction between
* `.js`, `.json` and `.node`.
*/
private File load(int priority) {
exists(int r | this.getEnclosingModule().searchRoot(this.getImportedPath(), _, r) |
deprecated private File load(int priority) {
exists(int r | this.getEnclosingModule().searchRoot(this.getImportedPathExpr(), _, r) |
result = loadAsFile(this, r, priority - prioritiesPerCandidate() * r) or
result =
loadAsDirectory(this, r,
Expand All @@ -415,7 +403,7 @@ class Require extends CallExpr, Import {
}

/** An argument to `require` or `require.resolve`, considered as a path expression. */
private class RequirePath extends PathExprCandidate {
deprecated private class RequirePath extends PathExprCandidate {
RequirePath() {
this = any(Require req).getArgument(0)
or
Expand All @@ -428,14 +416,14 @@ private class RequirePath extends PathExprCandidate {
}

/** A constant path element appearing in a call to `require` or `require.resolve`. */
private class ConstantRequirePathElement extends PathExpr, ConstantString {
deprecated private class ConstantRequirePathElement extends PathExpr, ConstantString {
ConstantRequirePathElement() { this = any(RequirePath rp).getAPart() }

override string getValue() { result = this.getStringValue() }
}

/** A `__dirname` path expression. */
private class DirNamePath extends PathExpr, VarAccess {
deprecated private class DirNamePath extends PathExpr, VarAccess {
DirNamePath() {
this.getName() = "__dirname" and
this.getVariable().getScope() instanceof ModuleScope
Expand All @@ -445,7 +433,7 @@ private class DirNamePath extends PathExpr, VarAccess {
}

/** A `__filename` path expression. */
private class FileNamePath extends PathExpr, VarAccess {
deprecated private class FileNamePath extends PathExpr, VarAccess {
FileNamePath() {
this.getName() = "__filename" and
this.getVariable().getScope() instanceof ModuleScope
Expand All @@ -458,7 +446,7 @@ private class FileNamePath extends PathExpr, VarAccess {
* A path expression of the form `path.join(p, "...")` where
* `p` is also a path expression.
*/
private class JoinedPath extends PathExpr, @call_expr {
deprecated private class JoinedPath extends PathExpr, @call_expr {
JoinedPath() {
exists(MethodCallExpr call | call = this |
call.getReceiver().(VarAccess).getName() = "path" and
Expand Down
Loading