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 ( import . meta. dirname , '../../tools/cds-lint/rules' ) ;
14+ const EXAMPLES_BASE_PATH = RULES_BASE_PATH
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 = ( ) => fs . globSync ( path . join ( RULES_BASE_PATH , '*/index.md' ) ) . sort ( )
22+
23+ /**
24+ * Generates the menu markdown file
25+ * by completely overriding its current contents.
26+ * The menu contains links to all rule description files
27+ * in alphabetical order.
28+ */
29+ function generateMenuMarkdown ( ) {
30+ const rules = getRuleDescriptionFiles ( ) ;
31+ const menu = rules . map ( rule => {
32+ const folderPath = path . posix . dirname ( path . relative ( RULES_BASE_PATH , rule ) ) ;
33+ const name = path . basename ( folderPath ) ;
34+ return `# [${ name } ](${ folderPath } /)`
35+ } ) . join ( '\n' ) ;
36+ const menuFilePath = path . join ( RULES_BASE_PATH , MENU_FILE_NAME )
37+ fs . writeFileSync ( menuFilePath , menu ) ;
38+ console . info ( `generated menu to ${ path . relative ( process . cwd ( ) , menuFilePath ) } ` ) ;
39+ }
40+
41+ /**
42+ * Generates a stub markdown file for a new JS rule.
43+ * The passed ruleName will be placed in the stub template
44+ * where $RULE_NAME is defined.
45+ * @param {string } ruleName - The name of the rule.
46+ */
47+ function generateJsRuleStub ( ruleName ) {
48+ if ( ! ruleName ) {
49+ console . error ( 'Please provide a rule name, e.g. "no-shared-handler-variables" as second argument' ) ;
50+ process . exit ( 1 ) ;
51+ }
52+ const stubFilePath = path . join ( RULES_BASE_PATH , ruleName , 'index.md' ) ;
53+ if ( fs . existsSync ( stubFilePath ) ) {
54+ console . error ( `file ${ stubFilePath } already exists, will not overwrite` ) ;
55+ process . exit ( 2 ) ;
56+ }
57+ fs . mkdirSync ( path . dirname ( stubFilePath ) , { recursive : true } ) ;
58+ const stub = fs . readFileSync ( path . join ( import . meta. dirname , 'js-rule-stub.md' ) , 'utf-8' ) . replaceAll ( '$RULE_NAME' , ruleName ) ;
59+ fs . writeFileSync ( stubFilePath , stub ) ;
60+ console . info ( `generated stub to ${ stubFilePath } ` ) ;
61+ const correctPath = path . join ( EXAMPLES_BASE_PATH , ruleName , 'correct' , 'srv' ) ;
62+ fs . mkdirSync ( correctPath , { recursive : true } ) ;
63+ const incorrectPath = path . join ( EXAMPLES_BASE_PATH , ruleName , 'incorrect' , 'srv' ) ;
64+ fs . mkdirSync ( incorrectPath , { recursive : true } ) ;
65+ console . info ( `generated example directories in ${ path . join ( EXAMPLES_BASE_PATH , ruleName ) } ` ) ;
66+ fs . writeFileSync ( path . join ( correctPath , 'admin-service.js' ) , '// correct example\n' ) ;
67+ fs . writeFileSync ( path . join ( incorrectPath , 'admin-service.js' ) , '// incorrect example\n' ) ;
68+ }
69+
70+ function main ( argv ) {
71+ switch ( argv [ 0 ] ) {
72+ case 'generate-menu' :
73+ generateMenuMarkdown ( ) ;
74+ break ;
75+ case 'generate-js-stub' :
76+ generateJsRuleStub ( argv [ 1 ] ) ;
77+ generateMenuMarkdown ( ) ;
78+ break ;
79+ default :
80+ console . log ( `Unknown command: ${ argv [ 0 ] } . Use one of: generate-menu, generate-stub` ) ;
81+ }
82+ }
83+
84+ main ( process . argv . slice ( 2 ) ) ;
0 commit comments