66 */
77
88private import codeql.yaml.Yaml as LibYaml
9+ private import codeql.files.FileSystem
910
1011private module YamlSig implements LibYaml:: InputSig {
1112 import codeql.Locations
@@ -49,6 +50,68 @@ private module YamlSig implements LibYaml::InputSig {
4950
5051import LibYaml:: Make< YamlSig >
5152
53+ /** A `qlpack.yml` document. */
54+ class QlPackDocument extends YamlDocument {
55+ QlPackDocument ( ) { this .getFile ( ) .getBaseName ( ) = [ "qlpack.yml" , "qlpack.test.yml" ] }
56+
57+ /** Gets the name of this QL pack. */
58+ string getPackName ( ) {
59+ exists ( YamlMapping n |
60+ n .getDocument ( ) = this and
61+ result = n .lookup ( "name" ) .( YamlScalar ) .getValue ( )
62+ )
63+ }
64+
65+ private string getADependencyName ( ) {
66+ exists ( YamlMapping n , YamlScalar key |
67+ n .getDocument ( ) = this and
68+ n .lookup ( "dependencies" ) .( YamlMapping ) .maps ( key , _) and
69+ result = key .getValue ( )
70+ )
71+ }
72+
73+ /** Gets a dependency of this QL pack. */
74+ QlPackDocument getADependency ( ) { result .getPackName ( ) = this .getADependencyName ( ) }
75+
76+ private Folder getRootFolder ( ) { result = this .getFile ( ) .getParentContainer ( ) }
77+
78+ /** Gets a folder inside this QL pack. */
79+ pragma [ nomagic]
80+ Folder getAFolder ( ) {
81+ result = this .getRootFolder ( )
82+ or
83+ exists ( Folder mid |
84+ mid = this .getAFolder ( ) and
85+ result .getParentContainer ( ) = mid and
86+ not result = any ( QlPackDocument other ) .getRootFolder ( )
87+ )
88+ }
89+ }
90+
91+ /**
92+ * Holds if `qlref` is a `.qlref` YAML document referencing a query
93+ * at relative path `relativePath`, and `f` is a candidate folder
94+ * in which to lookup the referenced query.
95+ *
96+ * `f` is either:
97+ * - the root of the QL pack containing `qlref`,
98+ * - the root of a QL pack that is a dependency of the QL pack containing `qlref`, or
99+ * - the folder containing `qlref`.
100+ */
101+ private predicate shouldAppend ( QlRefDocument qlref , Folder f , string relativePath ) {
102+ relativePath = qlref .getRelativeQueryPath ( ) and
103+ (
104+ exists ( QlPackDocument pack |
105+ pack .getAFolder ( ) = qlref .getFile ( ) .getParentContainer ( ) and
106+ f = [ pack , pack .getADependency ( ) ] .getFile ( ) .getParentContainer ( )
107+ )
108+ or
109+ f = qlref .getFile ( ) .getParentContainer ( )
110+ )
111+ }
112+
113+ private predicate shouldAppend ( Folder f , string relativePath ) { shouldAppend ( _, f , relativePath ) }
114+
52115/** A `.qlref` YAML document. */
53116class QlRefDocument extends YamlDocument {
54117 QlRefDocument ( ) { this .getFile ( ) .getExtension ( ) = "qlref" }
@@ -65,6 +128,24 @@ class QlRefDocument extends YamlDocument {
65128 )
66129 }
67130
131+ /** Gets the relative path of the query in this `.qlref` file. */
132+ string getRelativeQueryPath ( ) {
133+ exists ( YamlMapping n | n .getDocument ( ) = this |
134+ result = n .lookup ( "query" ) .( YamlScalar ) .getValue ( )
135+ )
136+ or
137+ not exists ( YamlMapping n | n .getDocument ( ) = this ) and
138+ result = this .eval ( ) .( YamlScalar ) .getValue ( )
139+ }
140+
141+ /** Gets the query file referenced in this `.qlref` file. */
142+ File getQueryFile ( ) {
143+ exists ( Folder f , string relativePath |
144+ shouldAppend ( this , f , relativePath ) and
145+ result = Folder:: Append< shouldAppend / 2 > :: append ( f , relativePath )
146+ )
147+ }
148+
68149 predicate isPrintAst ( ) {
69150 this .getFile ( ) .getStem ( ) = "PrintAst"
70151 or
0 commit comments