From 016805258240124cd85c4def57170d178afa2f32 Mon Sep 17 00:00:00 2001 From: btsimonh Date: Mon, 21 Nov 2022 18:39:33 +0000 Subject: [PATCH] add getcommands.js, can be run via npm run getcommands or node scripts/getcommands.js examines source for command registeration, moves stuff into comments and removes C strings.. --- package.json | 3 +- scripts/getcommands.js | 186 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 scripts/getcommands.js diff --git a/package.json b/package.json index cfc78c6bd..1a027178c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Gulp based script content builder", "main": "gulpfile.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "getcommands": "node scripts/getcommands.js" }, "repository": { "type": "git", diff --git a/scripts/getcommands.js b/scripts/getcommands.js new file mode 100644 index 000000000..72012f81f --- /dev/null +++ b/scripts/getcommands.js @@ -0,0 +1,186 @@ +let fs = require('fs'); + +let commands = []; +let cmdindex = {}; + +let inFile = 0; + +function mytrim(text){ + text = text.trim(); + if (text.startsWith('"')) text = text.slice(1, -1); + return text; +} + + +function getFolder(name, cb){ + //console.log('dir:'+name); + + let list = fs.readdirSync(name); + for (let i = 0; i < list.length; i++){ + let file = name + '/' + list[i]; + let s = fs.statSync(file); + + if (s.isDirectory()){ + getFolder(file, cb); + } else { + if (file.toLowerCase().endsWith('.c') || + file.toLowerCase().endsWith('.cpp')){ + inFile++; + //console.log('file:'+file); + let data = fs.readFileSync(file); + let text = data.toString('utf-8'); + let lines = text.split('\n'); + let newlines = []; + let modified = 0; + for (let i = 0; i < lines.length; i++){ + let line = lines[i].trim(); + // like CMD_RegisterCommand("SetChannel", "", CMD_SetChannel, "qqqqq0", NULL); + if (line.startsWith('//cmddetail:')){ + let commentlines = []; + let j; + for (j = i; j < lines.length; j++){ + let l = lines[j].trim(); + if (l.startsWith('//cmddetail:')){ + l = l.slice(12); + commentlines.push(l); + newlines.push(lines[j]); + } else { + break; + } + } + // move our parsing forward to skip all found + i = j; + let json = commentlines.join('\n'); + try{ + let cmd = JSON.parse(json); + if (cmdindex[cmd.name]){ + console.error('duplicate command docs at file: '+file+' line: '+line); + console.error(line); + } else { + commands.push(cmd); + cmdindex[cmd.name] = cmd; + } + } catch(e) { + console.error('error in json at file: '+file+' line: '+line); + console.error(json); + } + } + + // i may have changed... + line = lines[i].trim(); + + if (line.startsWith('CMD_RegisterCommand(')){ + line = line.slice('CMD_RegisterCommand('.length); + parts = line.split(','); + //cmddetail:{"name":"SetChannel", "args":"TODO", "fn":"CMD_SetChannel", "descr":"qqqqq0", "example":"", "file":""); + + let cmd = { + name: mytrim(parts[0]), + args: mytrim(parts[1]), + descr: mytrim(parts[3]), + fn: mytrim(parts[2]), + file: file.slice(6), + requires:"", + examples: "", + }; + + if (cmd.descr !== 'NULL'){ + console.log('replace "'+cmd.descr+'" with NULL'); + lines[i] = lines[i].replace('"'+cmd.descr+'"', 'NULL'); + modified++; + } + + if (!cmdindex[cmd.name]){ + // it did not have a doc line before + let json = JSON.stringify(cmd); + // insert CR at "fn": + json = json.split('"descr":'); + json = json.join('\n"descr":'); + json = json.split('"fn":'); + json = json.join('\n"fn":'); + json = json.split('"examples":'); + json = json.join('\n"examples":'); + let jsonlines = json.split('\n'); + for (let j = 0; j < jsonlines.length; j++){ + jsonlines[j] = '\t//cmddetail:'+jsonlines[j]; + } + newlines.push(... jsonlines); + modified++; + commands.push(cmd); + cmdindex[cmd.name] = cmd; + } + } + + newlines.push(lines[i]); + } + if (modified){ + let newdata = newlines.join('\n'); + try{ + fs.writeFileSync(file, newdata); + console.log('updated '+file); + } catch (e){ + console.error('failed to update '+file); + } + } + + inFile--; + + if (!inFile){ + //if (cb) cb(); + } + } + } + } +} + + +console.log('starting'); + +getFolder('./src'); + + +let mdshort = +`# Commands + +| Command | Arguments | Description | +|:------------- |:------------- | -----:| +`; + +let mdlong = +`# Commands + +| Command | Arguments | Description | Loc | +|:------------- |:-------------:|:----- | ------:| +`; + +for (let i = 0; i < commands.length; i++){ + + /* like: + | Command | Arguments | Description | + | ------------- |:-------------:| -----:| + | setChannel | [ChannelIndex][ChannelValue] | Sets a raw channel to given value. Relay channels are using 1 and 0 values. PWM channels are within [0,100] range. Do not use this for LED control, because there is a better and more advanced LED driver with dimming and configuration memory (remembers setting after on/off), LED driver commands has "led_" prefix. | + | addChannel | [ChannelIndex][ValueToAdd][ClampMin][ClampMax] | Ads a given value to the channel. Can be used to change PWM brightness. Clamp min and max arguments are optional. | + */ + let cmd = commands[i]; + + let textshort = `| ${cmd.name} | ${cmd.args}${cmd.requires?'\nReq:'+cmd.requires:''} | ${cmd.descr}${cmd.examples?'\ne.g.:'+cmd.examples:''} |`; + let textlong = `| ${cmd.name} | ${cmd.args}${cmd.requires?'\nReq:'+cmd.requires:''} | ${cmd.descr}${cmd.examples?'\ne.g.:'+cmd.examples:''} | ${cmd.file}\n${cmd.fn} |`; + + // allow multi-row entries in table entries. + textshort = textshort.replace(/\n/g, '
'); + textlong = textlong.replace(/\n/g, '
'); + + mdshort += textshort; + mdshort += '\n'; + mdlong += textlong; + mdlong += '\n'; +} + +mdshort += '\n'; +mdlong += '\n'; + +fs.writeFileSync('docs/commands.md', mdshort); +console.log('wrote commands.md'); +fs.writeFileSync('docs/commands-extended.md', mdlong); +console.log('wrote commands-extended.md'); +