Skip to content

JS: Move Directive subclasses into module and support "use client/server" #13303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/lib/semmle/javascript/AST.qll
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class TopLevel extends @toplevel, StmtContainer {
/** Gets the number of lines containing comments in this toplevel. */
int getNumberOfLinesOfComments() { numlines(this, _, _, result) }

override predicate isStrict() { this.getAStmt() instanceof StrictModeDecl }
override predicate isStrict() { this.getAStmt() instanceof Directive::StrictModeDecl }

override ControlFlowNode getFirstControlFlowNode() { result = this.getEntry() }

Expand Down
2 changes: 1 addition & 1 deletion javascript/ql/lib/semmle/javascript/Functions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine

override predicate isStrict() {
// check for explicit strict mode directive
exists(StrictModeDecl smd | this = smd.getContainer()) or
exists(Directive::StrictModeDecl smd | this = smd.getContainer()) or
// check for enclosing strict function
StmtContainer.super.isStrict() or
// all parts of a class definition are strict code
Expand Down
319 changes: 190 additions & 129 deletions javascript/ql/lib/semmle/javascript/Stmt.qll
Original file line number Diff line number Diff line change
Expand Up @@ -259,150 +259,211 @@ class Directive extends MaybeDirective {
}

/**
* A known directive, such as a strict mode declaration.
*
* Example:
*
* ```
* "use strict";
* ```
* Module containing subclasses of the `Directive` class.
*/
abstract class KnownDirective extends Directive { }
module Directive {
/**
* A known directive, such as a strict mode declaration.
*
* Example:
*
* ```
* "use strict";
* ```
*/
abstract class KnownDirective extends Directive { }

/**
* A strict mode declaration.
*
* Example:
*
* ```
* "use strict";
* ```
*/
class StrictModeDecl extends KnownDirective {
StrictModeDecl() { this.getDirectiveText() = "use strict" }
}
/**
* A strict mode declaration.
*
* Example:
*
* ```
* "use strict";
* ```
*/
class StrictModeDecl extends KnownDirective {
StrictModeDecl() { this.getDirectiveText() = "use strict" }
}

/**
* An asm.js directive.
*
* Example:
*
* ```
* "use asm";
* ```
*/
class AsmJSDirective extends KnownDirective {
AsmJSDirective() { this.getDirectiveText() = "use asm" }
}
/**
* An asm.js directive.
*
* Example:
*
* ```
* "use asm";
* ```
*/
class AsmJSDirective extends KnownDirective {
AsmJSDirective() { this.getDirectiveText() = "use asm" }
}

/**
* A Babel directive.
*
* Example:
*
* ```
* "use babel";
* ```
*/
class BabelDirective extends KnownDirective {
BabelDirective() { this.getDirectiveText() = "use babel" }
}
/**
* A Babel directive.
*
* Example:
*
* ```
* "use babel";
* ```
*/
class BabelDirective extends KnownDirective {
BabelDirective() { this.getDirectiveText() = "use babel" }
}

/**
* A legacy 6to5 directive.
*
* Example:
*
* ```
* "use 6to5";
* ```
*/
class SixToFiveDirective extends KnownDirective {
SixToFiveDirective() { this.getDirectiveText() = "use 6to5" }
}
/**
* A legacy 6to5 directive.
*
* Example:
*
* ```
* "use 6to5";
* ```
*/
class SixToFiveDirective extends KnownDirective {
SixToFiveDirective() { this.getDirectiveText() = "use 6to5" }
}

/**
* A SystemJS `format` directive.
*
* Example:
*
* ```
* "format global";
* ```
*/
class SystemJSFormatDirective extends KnownDirective {
SystemJSFormatDirective() {
this.getDirectiveText().regexpMatch("format (cjs|esm|global|register)")
/**
* A SystemJS `format` directive.
*
* Example:
*
* ```
* "format global";
* ```
*/
class SystemJSFormatDirective extends KnownDirective {
SystemJSFormatDirective() {
this.getDirectiveText().regexpMatch("format (cjs|esm|global|register)")
}
}
}

/**
* A SystemJS `format register` directive.
*
* Example:
*
* ```
* "format register";
* ```
*/
class FormatRegisterDirective extends SystemJSFormatDirective {
FormatRegisterDirective() { this.getDirectiveText() = "format register" }
}
/**
* A SystemJS `format register` directive.
*
* Example:
*
* ```
* "format register";
* ```
*/
class FormatRegisterDirective extends SystemJSFormatDirective {
FormatRegisterDirective() { this.getDirectiveText() = "format register" }
}

/**
* A `ngInject` or `ngNoInject` directive.
*
* Example:
*
* ```
* "ngInject";
* ```
*/
class NgInjectDirective extends KnownDirective {
NgInjectDirective() { this.getDirectiveText().regexpMatch("ng(No)?Inject") }
}
/**
* A `ngInject` or `ngNoInject` directive.
*
* Example:
*
* ```
* "ngInject";
* ```
*/
class NgInjectDirective extends KnownDirective {
NgInjectDirective() { this.getDirectiveText().regexpMatch("ng(No)?Inject") }
}

/**
* A YUI compressor directive.
*
* Example:
*
* ```
* "console:nomunge";
* ```
*/
class YuiDirective extends KnownDirective {
YuiDirective() {
this.getDirectiveText().regexpMatch("([a-z0-9_]+:nomunge, ?)*([a-z0-9_]+:nomunge)")
/**
* A YUI compressor directive.
*
* Example:
*
* ```
* "console:nomunge";
* ```
*/
class YuiDirective extends KnownDirective {
YuiDirective() {
this.getDirectiveText().regexpMatch("([a-z0-9_]+:nomunge, ?)*([a-z0-9_]+:nomunge)")
}
}
}

/**
* A SystemJS `deps` directive.
*
* Example:
*
* ```
* "deps fs";
* ```
*/
class SystemJSDepsDirective extends KnownDirective {
SystemJSDepsDirective() { this.getDirectiveText().regexpMatch("deps [^ ]+") }
}
/**
* A SystemJS `deps` directive.
*
* Example:
*
* ```
* "deps fs";
* ```
*/
class SystemJSDepsDirective extends KnownDirective {
SystemJSDepsDirective() { this.getDirectiveText().regexpMatch("deps [^ ]+") }
}

/**
* A `bundle` directive.
*
* Example:
*
* ```
* "bundle";
* ```
*/
class BundleDirective extends KnownDirective {
BundleDirective() { this.getDirectiveText() = "bundle" }
/**
* A `bundle` directive.
*
* Example:
*
* ```
* "bundle";
* ```
*/
class BundleDirective extends KnownDirective {
BundleDirective() { this.getDirectiveText() = "bundle" }
}

/**
* A `use server` directive.
*
* Example:
*
* ```
* "use server";
* ```
*/
class UseServerDirective extends KnownDirective {
UseServerDirective() { this.getDirectiveText() = "use server" }
}

/**
* A `use client` directive.
*
* Example:
*
* ```
* "use client";
* ```
*/
class UseClientDirective extends KnownDirective {
UseClientDirective() { this.getDirectiveText() = "use client" }
}
}

/** DEPRECATED. Use `Directive::KnownDirective` instead. */
deprecated class KnownDirective = Directive::KnownDirective;

/** DEPRECATED. Use `Directive::StrictModeDecl` instead. */
deprecated class StrictModeDecl = Directive::StrictModeDecl;

/** DEPRECATED. Use `Directive::AsmJSDirective` instead. */
deprecated class AsmJSDirective = Directive::AsmJSDirective;

/** DEPRECATED. Use `Directive::BabelDirective` instead. */
deprecated class BabelDirective = Directive::BabelDirective;

/** DEPRECATED. Use `Directive::SixToFiveDirective` instead. */
deprecated class SixToFiveDirective = Directive::SixToFiveDirective;

/** DEPRECATED. Use `Directive::SystemJSFormatDirective` instead. */
deprecated class SystemJSFormatDirective = Directive::SystemJSFormatDirective;

/** DEPRECATED. Use `Directive::NgInjectDirective` instead. */
deprecated class NgInjectDirective = Directive::NgInjectDirective;

/** DEPRECATED. Use `Directive::YuiDirective` instead. */
deprecated class YuiDirective = Directive::YuiDirective;

/** DEPRECATED. Use `Directive::SystemJSDepsDirective` instead. */
deprecated class SystemJSDepsDirective = Directive::SystemJSDepsDirective;

/** DEPRECATED. Use `Directive::BundleDirective` instead. */
deprecated class BundleDirective = Directive::BundleDirective;

/**
* An `if` statement.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ predicate isMultiLicenseBundle(TopLevel tl) {
/**
* Holds if this is a bundle with a "bundle" directive.
*/
predicate isDirectiveBundle(TopLevel tl) { exists(BundleDirective d | d.getTopLevel() = tl) }
predicate isDirectiveBundle(TopLevel tl) {
exists(Directive::BundleDirective d | d.getTopLevel() = tl)
}

/**
* Holds if toplevel `tl` contains code that looks like the output of a module bundler.
Expand Down
2 changes: 1 addition & 1 deletion javascript/ql/src/Expressions/UnknownDirective.ql
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import javascript

from Directive d
where
not d instanceof KnownDirective and
not d instanceof Directive::KnownDirective and
// ignore ":" pseudo-directive sometimes seen in dual-use shell/node.js scripts
not d.getExpr().getStringValue() = ":" and
// but exclude attribute top-levels: `<a href="javascript:'some-attribute-string'">`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import javascript

from KnownDirective d
from Directive::KnownDirective d
select d, d.getDirectiveText()
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
| UnknownDirective.js:12:5:12:17 | "use struct;" | Unknown directive: 'use struct;'. |
| UnknownDirective.js:13:5:13:17 | "Use Strict"; | Unknown directive: 'Use Strict'. |
| UnknownDirective.js:14:5:14:14 | "use bar"; | Unknown directive: 'use bar'. |
| UnknownDirective.js:38:5:38:17 | "[0, 0, 0];"; | Unknown directive: '[0, 0, 0];'. |
| UnknownDirective.js:39:5:39:65 | "[0, 0, ... , 0];"; | Unknown directive: '[0, 0, 0, 0, 0, 0, 0 ... (truncated)'. |
| UnknownDirective.js:45:5:45:15 | ":nomunge"; | Unknown directive: ':nomunge'. |
| UnknownDirective.js:46:5:46:30 | "foo(), ... munge"; | Unknown directive: 'foo(), bar, baz:nomu ... (truncated)'. |
| UnknownDirective.js:40:5:40:17 | "[0, 0, 0];"; | Unknown directive: '[0, 0, 0];'. |
| UnknownDirective.js:41:5:41:65 | "[0, 0, ... , 0];"; | Unknown directive: '[0, 0, 0, 0, 0, 0, 0 ... (truncated)'. |
| UnknownDirective.js:47:5:47:15 | ":nomunge"; | Unknown directive: ':nomunge'. |
| UnknownDirective.js:48:5:48:30 | "foo(), ... munge"; | Unknown directive: 'foo(), bar, baz:nomu ... (truncated)'. |
Loading