11#!/usr/bin/env npx tsx
22
3- /**
3+ /*
44 * Updates src/languages/builtin.json by querying the CodeQL CLI for:
55 * - Languages that have default queries (via codeql-extractor.yml)
66 * - Language aliases (via `codeql resolve languages --format=betterjson --extractor-include-aliases`)
@@ -19,69 +19,107 @@ import * as yaml from "yaml";
1919
2020import { BUILTIN_LANGUAGES_FILE } from "./config" ;
2121
22- const codeqlPath = process . argv [ 2 ] || "codeql" ;
22+ /** Resolve all known language extractor directories. */
23+ function resolveLanguages ( codeqlPath : string ) : Record < string , string [ ] > {
24+ return JSON . parse (
25+ execFileSync ( codeqlPath , [ "resolve" , "languages" , "--format=json" ] , {
26+ encoding : "utf8" ,
27+ } ) ,
28+ ) as Record < string , string [ ] > ;
29+ }
2330
24- // Step 1: Resolve all language extractor directories.
25- const resolveJson : Record < string , string [ ] > = JSON . parse (
26- execFileSync ( codeqlPath , [ "resolve" , "languages" , "--format=json" ] , {
27- encoding : "utf8" ,
28- } ) ,
29- ) ;
31+ /**
32+ * Return the sorted list of languages whose extractors ship default queries.
33+ *
34+ * @param extractorDirs - Map from language to list of extractor directories
35+ */
36+ function findLanguagesWithDefaultQueries (
37+ extractorDirs : Record < string , string [ ] > ,
38+ ) : string [ ] {
39+ const languages : string [ ] = [ ] ;
40+
41+ for ( const [ language , dirs ] of Object . entries ( extractorDirs ) ) {
42+ if ( dirs . length !== 1 ) {
43+ throw new Error (
44+ `Expected exactly one extractor directory for language '${ language } ', but found ${ dirs . length } : ${ dirs . join (
45+ ", " ,
46+ ) } `,
47+ ) ;
48+ }
49+
50+ const extractorYmlPath = path . join ( dirs [ 0 ] , "codeql-extractor.yml" ) ;
51+
52+ if ( ! fs . existsSync ( extractorYmlPath ) ) {
53+ throw new Error (
54+ `Extractor YAML not found for language '${ language } ' at expected path: ${ extractorYmlPath } ` ,
55+ ) ;
56+ }
57+
58+ const extractorYml = yaml . parse ( fs . readFileSync ( extractorYmlPath , "utf8" ) ) ;
59+ const defaultQueries : unknown [ ] | undefined = extractorYml . default_queries ;
60+
61+ if ( Array . isArray ( defaultQueries ) && defaultQueries . length > 0 ) {
62+ console . log (
63+ ` ✅ ${ language } : included (default queries: ${ JSON . stringify ( defaultQueries ) } )` ,
64+ ) ;
65+ languages . push ( language ) ;
66+ } else {
67+ console . log ( ` ❌ ${ language } : excluded (no default queries)` ) ;
68+ }
69+ }
3070
31- // Step 2: For each language, read codeql-extractor.yml and check default_queries.
32- const languages : string [ ] = [ ] ;
71+ return languages . sort ( ) ;
72+ }
3373
34- for ( const [ language , dirs ] of Object . entries ( resolveJson ) ) {
35- const extractorDir = dirs [ 0 ] ;
36- const extractorYmlPath = path . join ( extractorDir , "codeql-extractor.yml" ) ;
74+ /**
75+ * Resolve language aliases from the CodeQL CLI, keeping only those whose
76+ * target is in the given set of included languages.
77+ */
78+ function resolveAliases (
79+ codeqlPath : string ,
80+ includedLanguages : Set < string > ,
81+ ) : Record < string , string > {
82+ const betterjsonOutput = JSON . parse (
83+ execFileSync (
84+ codeqlPath ,
85+ [
86+ "resolve" ,
87+ "languages" ,
88+ "--format=betterjson" ,
89+ "--extractor-include-aliases" ,
90+ ] ,
91+ { encoding : "utf8" } ,
92+ ) ,
93+ ) ;
94+
95+ return Object . fromEntries (
96+ Object . entries ( ( betterjsonOutput . aliases ?? { } ) as Record < string , string > )
97+ . filter ( ( [ , target ] ) => includedLanguages . has ( target ) )
98+ . sort ( ( [ a ] , [ b ] ) => a . localeCompare ( b ) ) ,
99+ ) ;
100+ }
37101
38- if ( ! fs . existsSync ( extractorYmlPath ) ) {
39- throw new Error (
40- `Extractor YAML not found for language '${ language } ' at expected path: ${ extractorYmlPath } ` ,
41- ) ;
42- }
102+ /** Write the built-in languages data to disk. */
103+ function writeBuiltinLanguages (
104+ languages : string [ ] ,
105+ aliases : Record < string , string > ,
106+ ) : void {
107+ const content = `${ JSON . stringify ( { languages, aliases } , null , 2 ) } \n` ;
108+ fs . mkdirSync ( path . dirname ( BUILTIN_LANGUAGES_FILE ) , { recursive : true } ) ;
109+ fs . writeFileSync ( BUILTIN_LANGUAGES_FILE , content ) ;
110+
111+ console . log ( `\nWrote ${ BUILTIN_LANGUAGES_FILE } ` ) ;
112+ console . log ( ` Languages: ${ languages . join ( ", " ) } ` ) ;
113+ console . log ( ` Aliases: ${ Object . keys ( aliases ) . join ( ", " ) } ` ) ;
114+ }
43115
44- const extractorYml = yaml . parse ( fs . readFileSync ( extractorYmlPath , "utf8" ) ) ;
45- const defaultQueries : unknown [ ] | undefined = extractorYml . default_queries ;
116+ function main ( ) : void {
117+ const codeqlPath = process . argv [ 2 ] || "codeql" ;
46118
47- if ( Array . isArray ( defaultQueries ) && defaultQueries . length > 0 ) {
48- console . log (
49- ` ✅ ${ language } : included (default queries: ${ JSON . stringify ( defaultQueries ) } )` ,
50- ) ;
51- languages . push ( language ) ;
52- } else {
53- console . log ( ` ❌ ${ language } : excluded (no default queries)` ) ;
54- }
119+ const extractorDirs = resolveLanguages ( codeqlPath ) ;
120+ const languages = findLanguagesWithDefaultQueries ( extractorDirs ) ;
121+ const aliases = resolveAliases ( codeqlPath , new Set ( languages ) ) ;
122+ writeBuiltinLanguages ( languages , aliases ) ;
55123}
56124
57- languages . sort ( ) ;
58-
59- // Step 3: Resolve aliases, filtered to only those targeting included languages.
60- const betterjsonOutput = JSON . parse (
61- execFileSync (
62- codeqlPath ,
63- [
64- "resolve" ,
65- "languages" ,
66- "--format=betterjson" ,
67- "--extractor-include-aliases" ,
68- ] ,
69- { encoding : "utf8" } ,
70- ) ,
71- ) ;
72-
73- const languageSet = new Set ( languages ) ;
74- const aliases : Record < string , string > = Object . fromEntries (
75- Object . entries ( ( betterjsonOutput . aliases ?? { } ) as Record < string , string > )
76- . filter ( ( [ , target ] ) => languageSet . has ( target ) )
77- . sort ( ( [ a ] , [ b ] ) => a . localeCompare ( b ) ) ,
78- ) ;
79-
80- // Step 4: Update the built-in languages file.
81- const content = `${ JSON . stringify ( { languages, aliases } , null , 2 ) } \n` ;
82- fs . mkdirSync ( path . dirname ( BUILTIN_LANGUAGES_FILE ) , { recursive : true } ) ;
83- fs . writeFileSync ( BUILTIN_LANGUAGES_FILE , content ) ;
84-
85- console . log ( `\nWrote ${ BUILTIN_LANGUAGES_FILE } ` ) ;
86- console . log ( ` Languages: ${ languages . join ( ", " ) } ` ) ;
87- console . log ( ` Aliases: ${ Object . keys ( aliases ) . join ( ", " ) } ` ) ;
125+ main ( ) ;
0 commit comments