1+ #!/usr/bin/env node
2+
3+ // eslint plugin rule utility
4+ // ============================
5+ // node index.js generate-menu
6+ // generates the _menu.md file to make sure all rules are included.
7+ // node index.js generate-js-stub <rule-name>
8+ // generates a stub markdown file for a new JS rule with name <rule-name>.
9+
10+ import * as fs from 'node:fs'
11+ import * as path from 'node:path'
12+
13+ const RULES_BASE_PATH = path . join ( 'tools' , 'cds-lint' , 'rules' ) ;
14+ const EXAMPLES_BASE_PATH = path . join ( 'tools' , 'cds-lint' , 'examples' ) ;
15+ const MENU_FILE_NAME = '_menu.md' ;
16+
17+ /**
18+ * Get a list of all rule description files.
19+ * @returns {string[] } An array of rule description file names.
20+ */
21+ const getRuleDescriptionFiles = ( ) =>
22+ fs . readdirSync ( RULES_BASE_PATH )
23+ . filter ( file => file . endsWith ( '.md' ) )
24+ . filter ( file => ! [ 'index.md' , MENU_FILE_NAME ] . includes ( file ) )
25+ . sort ( )
26+
27+ /**
28+ * Generates the menu markdown file
29+ * by completely overriding its current contents.
30+ * The menu contains links to all rule description files
31+ * in alphabetical order.
32+ */
33+ function generateMenuMarkdown ( ) {
34+ const rules = getRuleDescriptionFiles ( ) ;
35+ const menu = rules . map ( rule => {
36+ const clean = rule . replace ( '.md' , '' ) ;
37+ return `# [${ clean } ](${ clean } )`
38+ } ) . join ( '\n' ) ;
39+ const menuFilePath = path . join ( RULES_BASE_PATH , '_menu.md' )
40+ fs . writeFileSync ( menuFilePath , menu ) ;
41+ console . info ( `generated menu to ${ menuFilePath } ` )
42+ }
43+
44+ /**
45+ * Generates a stub markdown file for a new JS rule.
46+ * The passed ruleName will be placed in the stub template
47+ * where $RULE_NAME is defined.
48+ * @param {string } ruleName - The name of the rule.
49+ */
50+ function generateJsRuleStub ( ruleName ) {
51+ if ( ! ruleName ) {
52+ console . error ( 'Please provide a rule name, e.g. "no-shared-handler-variables" as second argument' ) ;
53+ process . exit ( 1 ) ;
54+ }
55+ const stubFilePath = path . join ( RULES_BASE_PATH , ruleName + '.md' ) ;
56+ if ( fs . existsSync ( stubFilePath ) ) {
57+ console . error ( `file ${ stubFilePath } already exists, will not overwrite` ) ;
58+ process . exit ( 2 ) ;
59+ }
60+ const stub = fs . readFileSync ( path . join ( import . meta. dirname , 'js-rule-stub.md' ) , 'utf-8' ) . replaceAll ( '$RULE_NAME' , ruleName ) ;
61+ fs . writeFileSync ( stubFilePath , stub ) ;
62+ console . info ( `generated stub to ${ stubFilePath } ` ) ;
63+ const correctPath = path . join ( EXAMPLES_BASE_PATH , ruleName , 'correct' , 'srv' ) ;
64+ fs . mkdirSync ( correctPath , { recursive : true } ) ;
65+ const incorrectPath = path . join ( EXAMPLES_BASE_PATH , ruleName , 'incorrect' , 'srv' ) ;
66+ fs . mkdirSync ( incorrectPath , { recursive : true } ) ;
67+ console . info ( `generated example directories in ${ path . join ( EXAMPLES_BASE_PATH , ruleName ) } ` ) ;
68+ fs . writeFileSync ( path . join ( correctPath , 'admin-service.js' ) , '// correct example\n' ) ;
69+ fs . writeFileSync ( path . join ( incorrectPath , 'admin-service.js' ) , '// incorrect example\n' ) ;
70+ }
71+
72+ function main ( argv ) {
73+ switch ( argv [ 0 ] ) {
74+ case 'generate-menu' :
75+ generateMenuMarkdown ( ) ;
76+ break ;
77+ case 'generate-js-stub' :
78+ generateJsRuleStub ( argv [ 1 ] ) ;
79+ generateMenuMarkdown ( ) ;
80+ break ;
81+ default :
82+ console . log ( `Unknown command: ${ argv [ 0 ] } . Use one of: generate-menu, generate-stub` ) ;
83+ }
84+ }
85+
86+ main ( process . argv . slice ( 2 ) ) ;
0 commit comments