@@ -24,9 +24,11 @@ abstract class Module extends TopLevel {
2424 Module getAnImportedModule ( ) { result = getAnImport ( ) .getImportedModule ( ) }
2525
2626 /** Gets a symbol exported by this module. */
27- string getAnExportedSymbol ( ) { exports ( result , _ ) }
27+ string getAnExportedSymbol ( ) { exists ( getAnExportedValue ( result ) ) }
2828
2929 /**
30+ * DEPRECATED. Use `getAnExportedValue` instead.
31+ *
3032 * Holds if this module explicitly exports symbol `name` at the
3133 * program element `export`.
3234 *
@@ -36,9 +38,77 @@ abstract class Module extends TopLevel {
3638 * that are explicitly defined on the module object.
3739 *
3840 * Symbols defined in another module that are re-exported by
39- * this module are not considered either.
41+ * this module are only sometimes considered.
42+ */
43+ deprecated predicate exports ( string name , ASTNode export ) {
44+ this instanceof AmdModule and
45+ exists ( DataFlow:: PropWrite pwn | export = pwn .getAstNode ( ) |
46+ pwn .getBase ( ) .analyze ( ) .getAValue ( ) = this .( AmdModule ) .getDefine ( ) .getAModuleExportsValue ( ) and
47+ name = pwn .getPropertyName ( )
48+ )
49+ or
50+ this instanceof Closure:: ClosureModule and
51+ exists ( DataFlow:: PropWrite write , Expr base |
52+ write .getAstNode ( ) = export and
53+ write .writes ( base .flow ( ) , name , _) and
54+ (
55+ base = this .( Closure:: ClosureModule ) .getExportsVariable ( ) .getAReference ( )
56+ or
57+ base = this .( Closure:: ClosureModule ) .getExportsVariable ( ) .getAnAssignedExpr ( )
58+ )
59+ )
60+ or
61+ this instanceof NodeModule and
62+ (
63+ // a property write whose base is `exports` or `module.exports`
64+ exists ( DataFlow:: PropWrite pwn | export = pwn .getAstNode ( ) |
65+ pwn .getBase ( ) = this .( NodeModule ) .getAModuleExportsNode ( ) and
66+ name = pwn .getPropertyName ( )
67+ )
68+ or
69+ // a re-export using spread-operator. E.g. `const foo = require("./foo"); module.exports = {bar: bar, ...foo};`
70+ exists ( ObjectExpr obj | obj = this .( NodeModule ) .getAModuleExportsNode ( ) .asExpr ( ) |
71+ obj
72+ .getAProperty ( )
73+ .( SpreadProperty )
74+ .getInit ( )
75+ .( SpreadElement )
76+ .getOperand ( )
77+ .flow ( )
78+ .getALocalSource ( )
79+ .asExpr ( )
80+ .( Import )
81+ .getImportedModule ( )
82+ .exports ( name , export )
83+ )
84+ or
85+ // an externs definition (where appropriate)
86+ exists ( PropAccess pacc | export = pacc |
87+ pacc .getBase ( ) = this .( NodeModule ) .getAModuleExportsNode ( ) .asExpr ( ) and
88+ name = pacc .getPropertyName ( ) and
89+ isExterns ( ) and
90+ exists ( pacc .getDocumentation ( ) )
91+ )
92+ )
93+ or
94+ this instanceof ES2015Module and
95+ exists ( ExportDeclaration ed | ed = this .( ES2015Module ) .getAnExport ( ) and ed = export |
96+ ed .exportsAs ( _, name )
97+ )
98+ }
99+
100+ /**
101+ * Get a value that is explicitly exported from this module with under `name`.
102+ *
103+ * Note that in some module systems (notably CommonJS and AMD)
104+ * modules are arbitrary objects that export all their
105+ * properties. This predicate only considers properties
106+ * that are explicitly defined on the module object.
107+ *
108+ * Symbols defined in another module that are re-exported by
109+ * this module are only sometimes considered.
40110 */
41- abstract predicate exports ( string name , ASTNode export ) ;
111+ abstract DataFlow :: Node getAnExportedValue ( string name ) ;
42112
43113 /**
44114 * Gets the root folder relative to which the given import path (which must
0 commit comments