@@ -11,15 +11,17 @@ const dirname = path.dirname(new URL(import.meta.url).pathname);
1111
1212const parseAllToJSON = yamlContent => YAML . parseAllDocuments ( yamlContent ) . map ( doc => doc . toJSON ( ) ) ;
1313
14+ export const description = 'Verify one or more files using an AST-Grep preset.' ;
15+
1416export function help ( ) {
1517 console . log ( `Usage: vg ast-check <preset> <files...>
1618
17- Verify one or more files using an AST‑Grep preset.
19+ ${ description }
1820
1921Arguments:
20- <preset> Name of the preset to use. Presets are located in the "rules"
22+ <preset> Name of the preset to use. Presets are located in the "rules"
2123 directory next to this script and can be YAML or JS files.
22- <files...> One or more files to verify. Shell glob expansion happens
24+ <files...> One or more files to verify. Shell glob expansion happens
2325 outside this tool, so pass files directly.
2426` ) ;
2527
@@ -28,7 +30,6 @@ Arguments:
2830 . readdirSync ( path . resolve ( dirname , '../rules' ) )
2931 . filter ( file => file . endsWith ( '.yaml' ) || file . endsWith ( '.yml' ) || file . endsWith ( '.js' ) ) ;
3032
31- const examples = [ ] ;
3233 console . log ( 'Available presets:' ) ;
3334 for ( const rule of rules ) {
3435 // eslint-disable-next-line security/detect-non-literal-fs-filename
@@ -42,27 +43,23 @@ Arguments:
4243 for ( const ruleData of rules ) {
4344 console . log ( ` ${ ruleData . id || '(unnamed)' } - ${ ruleData . description || 'No description provided.' } ` ) ;
4445 if ( ruleData . args && Array . isArray ( ruleData . args ) ) {
45- examples . push ( ` vg ast-check ${ ruleName } ${ ruleData . args . join ( ' ' ) } `) ;
46+ console . log ( ` Example: vg ast-check ${ ruleName } ${ ruleData . args . join ( ' ' ) } `) ;
4647 }
4748 }
4849 }
49- if ( examples . length > 0 ) {
50- console . log ( '\nExample usage:' ) ;
51- for ( const example of examples ) {
52- console . log ( ` ${ example } ` ) ;
53- }
54- }
5550}
5651
5752export default async function run ( ...args ) {
5853 if ( args . length === 0 ) {
5954 console . error ( 'Error: no preset specified for ast-check command.' ) ;
55+ help ( ) ;
6056 return ;
6157 }
6258 const preset = args . shift ( ) ;
6359 const files = args ;
6460 if ( files . length === 0 ) {
6561 console . error ( 'Error: no files provided for ast-check command.' ) ;
62+ help ( ) ;
6663 return ;
6764 }
6865 // Resolve the preset file.
@@ -132,13 +129,14 @@ export default async function run(...args) {
132129 const matches = root . findAll ( matcher ) ;
133130 if ( matches . length > 0 ) {
134131 hasViolation = isFatalRule || hasViolation ;
135- console . error ( `❌ FAIL ${ file } : found ${ matches . length } violation(s) for rule '${ id } '.` ) ;
132+ console . error (
133+ `${ isFatalRule ? '🔴 FAIL' : '🟡 SKIP' } ${ file } : found ${ matches . length } violation(s) for rule '${ id } '.`
134+ ) ;
136135 // Print custom message from the rule if provided.
137136 if ( rule . message ) {
138137 console . error ( ` ${ rule . severity || 'note' } : ${ rule . message } ` ) ;
139138 }
140139 try {
141- // Extract 1‑based line numbers for each match using ast‑grep's range API.
142140 const lines = matches . map ( node => {
143141 const rng = node . range ( ) ;
144142 return rng . start . line + 1 ;
@@ -153,7 +151,7 @@ export default async function run(...args) {
153151 console . error ( ` ${ file } : <unable to determine line numbers>` ) ;
154152 }
155153 } else {
156- console . log ( `✅ PASS ${ file } : ${ id } .` ) ;
154+ console . log ( `🟢 PASS ${ file } : ${ id } .` ) ;
157155 }
158156 }
159157 }
0 commit comments