@@ -403,57 +403,83 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
403403 *
404404 * For compatibility with old transpilers, we treat `import * from '...'`
405405 * as a default import as well.
406+ *
407+ * Additional import nodes can be added by subclassing `ModuleImportNode::Range`.
406408 */
407409class ModuleImportNode extends DataFlow:: SourceNode {
408- string path ;
410+ ModuleImportNode :: Range range ;
409411
410- ModuleImportNode ( ) {
411- // `require("http")`
412- exists ( Require req | req .getImportedPath ( ) .getValue ( ) = path | this = DataFlow:: valueNode ( req ) )
413- or
414- // `import http = require("http")`
415- exists ( ExternalModuleReference req | req .getImportedPath ( ) .getValue ( ) = path |
416- this = DataFlow:: valueNode ( req )
417- )
418- or
419- // `import * as http from 'http'` or `import http from `http`'
420- exists ( ImportDeclaration id , ImportSpecifier is , SsaExplicitDefinition ssa |
421- id .getImportedPath ( ) .getValue ( ) = path and
422- is = id .getASpecifier ( ) and
423- ssa .getDef ( ) = is and
424- this = DataFlow:: ssaDefinitionNode ( ssa )
425- |
426- is instanceof ImportNamespaceSpecifier and
427- count ( id .getASpecifier ( ) ) = 1
428- or
429- is .getImportedName ( ) = "default"
430- )
431- or
432- // `import { createServer } from 'http'`
433- exists ( ImportDeclaration id |
434- this = DataFlow:: destructuredModuleImportNode ( id ) and
435- id .getImportedPath ( ) .getValue ( ) = path
436- )
437- or
438- // declared AMD dependency
439- exists ( AMDModuleDefinition amd |
440- this = DataFlow:: parameterNode ( amd .getDependencyParameter ( path ) )
441- )
442- or
443- // AMD require
444- exists ( AMDModuleDefinition amd , CallExpr req |
445- req = amd .getARequireCall ( ) and
446- this = DataFlow:: valueNode ( req ) and
447- path = req .getArgument ( 0 ) .( ConstantString ) .getStringValue ( )
448- )
449- }
412+ ModuleImportNode ( ) { this = range }
450413
451414 /** Gets the path of the imported module. */
452- string getPath ( ) { result = path }
415+ string getPath ( ) { result = range .getPath ( ) }
416+ }
417+
418+ module ModuleImportNode {
419+ /**
420+ * A data flow node that refers to an imported module.
421+ */
422+ abstract class Range extends DataFlow:: SourceNode {
423+ /** Gets the path of the imported module. */
424+ abstract string getPath ( ) ;
425+ }
426+
427+ private class DefaultRange extends Range {
428+ string path ;
429+
430+ DefaultRange ( ) {
431+ // `require("http")`
432+ exists ( Require req | req .getImportedPath ( ) .getValue ( ) = path |
433+ this = DataFlow:: valueNode ( req )
434+ )
435+ or
436+ // `import http = require("http")`
437+ exists ( ExternalModuleReference req | req .getImportedPath ( ) .getValue ( ) = path |
438+ this = DataFlow:: valueNode ( req )
439+ )
440+ or
441+ // `import * as http from 'http'` or `import http from `http`'
442+ exists ( ImportDeclaration id , ImportSpecifier is , SsaExplicitDefinition ssa |
443+ id .getImportedPath ( ) .getValue ( ) = path and
444+ is = id .getASpecifier ( ) and
445+ ssa .getDef ( ) = is and
446+ this = DataFlow:: ssaDefinitionNode ( ssa )
447+ |
448+ is instanceof ImportNamespaceSpecifier and
449+ count ( id .getASpecifier ( ) ) = 1
450+ or
451+ is .getImportedName ( ) = "default"
452+ )
453+ or
454+ // `import { createServer } from 'http'`
455+ exists ( ImportDeclaration id |
456+ this = DataFlow:: destructuredModuleImportNode ( id ) and
457+ id .getImportedPath ( ) .getValue ( ) = path
458+ )
459+ or
460+ // declared AMD dependency
461+ exists ( AMDModuleDefinition amd |
462+ this = DataFlow:: parameterNode ( amd .getDependencyParameter ( path ) )
463+ )
464+ or
465+ // AMD require
466+ exists ( AMDModuleDefinition amd , CallExpr req |
467+ req = amd .getARequireCall ( ) and
468+ this = DataFlow:: valueNode ( req ) and
469+ path = req .getArgument ( 0 ) .( ConstantString ) .getStringValue ( )
470+ )
471+ }
472+
473+ /** Gets the path of the imported module. */
474+ override string getPath ( ) { result = path }
475+ }
453476}
454477
455478/**
456- * Gets a (default) import of the module with the given path.
479+ * Gets a (default) import of the module with the given path, such as `require("fs")`
480+ * or `import * as fs from "fs"`.
481+ *
482+ * This predicate can be extended by subclassing `ModuleImportNode::Range`.
457483 */
458484ModuleImportNode moduleImport ( string path ) { result .getPath ( ) = path }
459485
0 commit comments