Merge pull request #13303 from asgerf/js/use-server-and-client

JS: Move Directive subclasses into module and support "use client/server"
This commit is contained in:
Asger F
2024-04-02 15:13:45 +02:00
committed by GitHub
8 changed files with 206 additions and 141 deletions

View File

@@ -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() }

View File

@@ -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

View File

@@ -259,149 +259,210 @@ 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 `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 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 `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" }
}
}
/**
* A SystemJS `format register` directive.
*
* Example:
*
* ```
* "format register";
* ```
*/
class FormatRegisterDirective extends SystemJSFormatDirective {
FormatRegisterDirective() { this.getDirectiveText() = "format register" }
}
/** DEPRECATED. Use `Directive::KnownDirective` instead. */
deprecated class KnownDirective = Directive::KnownDirective;
/**
* A `ngInject` or `ngNoInject` directive.
*
* Example:
*
* ```
* "ngInject";
* ```
*/
class NgInjectDirective extends KnownDirective {
NgInjectDirective() { this.getDirectiveText().regexpMatch("ng(No)?Inject") }
}
/** DEPRECATED. Use `Directive::StrictModeDecl` instead. */
deprecated class StrictModeDecl = Directive::StrictModeDecl;
/**
* A YUI compressor directive.
*
* Example:
*
* ```
* "console:nomunge";
* ```
*/
class YuiDirective extends KnownDirective {
YuiDirective() {
this.getDirectiveText().regexpMatch("([a-z0-9_]+:nomunge, ?)*([a-z0-9_]+:nomunge)")
}
}
/** DEPRECATED. Use `Directive::AsmJSDirective` instead. */
deprecated class AsmJSDirective = Directive::AsmJSDirective;
/**
* A SystemJS `deps` directive.
*
* Example:
*
* ```
* "deps fs";
* ```
*/
class SystemJSDepsDirective extends KnownDirective {
SystemJSDepsDirective() { this.getDirectiveText().regexpMatch("deps [^ ]+") }
}
/** DEPRECATED. Use `Directive::BabelDirective` instead. */
deprecated class BabelDirective = Directive::BabelDirective;
/**
* A `bundle` directive.
*
* Example:
*
* ```
* "bundle";
* ```
*/
class BundleDirective extends KnownDirective {
BundleDirective() { this.getDirectiveText() = "bundle" }
}
/** 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.

View File

@@ -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.

View File

@@ -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'">`

View File

@@ -1,4 +1,4 @@
import javascript
from KnownDirective d
from Directive::KnownDirective d
select d, d.getDirectiveText()

View File

@@ -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)'. |

View File

@@ -32,6 +32,8 @@ function good() {
"ngNoInject"; // OK
"deps foo"; // OK
"deps bar"; // OK
"use server"; // OK
"use client"; // OK
}
function data() {
@@ -46,6 +48,6 @@ function yui() {
"foo(), bar, baz:nomunge"; // NOT OK
}
function babel_typeof(obj) {
function babel_typeof(obj) {
"@babel/helpers - typeof"
}
}