|
| 1 | +import { Command, program } from 'commander'; |
| 2 | +import { Sqomplexity } from './sqomplexity.js'; |
| 3 | +import path from 'path'; |
| 4 | +import { fileURLToPath } from 'url'; |
| 5 | +import * as fs from 'node:fs/promises'; |
| 6 | + |
| 7 | +const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 8 | +process.chdir(__dirname); |
| 9 | + |
| 10 | +const art = ` |
| 11 | + _____ ____ _ _ _ |
| 12 | + / ____| / __ \\ | | (_)| | |
| 13 | + | (___ | | | | ___ _ __ ___ _ __ | | ___ __ __ _ | |_ _ _ |
| 14 | + \\___ \\ | | | | / _ \\ | '_ \` _ \\ | '_ \\ | | / _ \\\\ \\/ /| || __|| | | | |
| 15 | + ____) || |__| || (_) || | | | | || |_) || |____| __/ > < | || |_ | |_| | |
| 16 | + |_____/ \\___\\_\\ \\___/ |_| |_| |_|| .__/ |______|\\___|/_/\\_\\|_| \\__| \\__, | |
| 17 | + | | __/ | |
| 18 | + Calculate complexity scores |_| for SQL queries |___/ |
| 19 | + |
| 20 | +`; |
| 21 | + |
| 22 | +export default function() { |
| 23 | + return (new Command()) |
| 24 | + .name('SQompLexity') |
| 25 | + // .description('Determine the SQL complexity score for a single SQL SELECT-query.') |
| 26 | + .description(art + '\nAuthor:\n BertW') |
| 27 | + .version(typeof VERSION !== 'undefined' ? VERSION : '0') |
| 28 | + .argument('queries...', 'one or multiple SQL queries (space separated or quoted)') |
| 29 | + .option('-f, --files', 'assumes the given arguments/queries are filepaths, and it will read the contents from them. Every file is expected to contain 1 query; if not, their complexity is summed') |
| 30 | + .option('-b, --base64', 'assumes the given arguments/queries are base64 encoded') |
| 31 | + .option('-s, --score', 'output only the complexity score. -1 will be returned if an error occurs') |
| 32 | + .option('-w, --weights <weights>', 'takes a path to a json file that defines a custom set of weights') |
| 33 | + .option('-a, --all', 'returns all data including the AST') |
| 34 | + .option('-p, --pretty-print', 'output JSON with indentation and newlines', false) |
| 35 | + .showHelpAfterError() |
| 36 | + .action(async(queries, options) => { |
| 37 | + if (options.files) { |
| 38 | + queries = await Promise.all(queries.map(async(path) => (await fs.readFile(path)).toString())); |
| 39 | + } |
| 40 | + |
| 41 | + if (options.base64) { |
| 42 | + queries = queries.map((query) => Buffer.from(query, 'base64').toString('utf8')); |
| 43 | + } |
| 44 | + |
| 45 | + const fn = options.score ? 'score' : 'analyze'; |
| 46 | + |
| 47 | + const weights = await (async function() { |
| 48 | + if (!options.weights) { |
| 49 | + return; |
| 50 | + } |
| 51 | + if (options.weights.endsWith('.json')) { |
| 52 | + return JSON.parse(await fs.readFile(options.weights, { encoding: 'utf8' })); |
| 53 | + } |
| 54 | + if (options.weights.endsWith('.js')) { |
| 55 | + const { default: weights } = await import( |
| 56 | + /* webpackIgnore: true */ |
| 57 | + options.weights |
| 58 | + ); |
| 59 | + return weights; |
| 60 | + } |
| 61 | + |
| 62 | + throw program.error('Weights should be a .js or .json file.'); |
| 63 | + })(); |
| 64 | + |
| 65 | + /** @var {number[]|object[]} results */ |
| 66 | + const results = await (new Sqomplexity(queries, weights))[fn](); |
| 67 | + |
| 68 | + if (!options.all) { |
| 69 | + results.map((result) => { |
| 70 | + if (typeof result === 'object') { |
| 71 | + for (const [key] of Object.entries(result)) { |
| 72 | + if (['stats', 'complexity'].indexOf(key) === -1) { |
| 73 | + delete result[key]; |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + return result; |
| 78 | + }); |
| 79 | + } |
| 80 | + |
| 81 | + process.stdout.write(JSON.stringify(results, null, options.prettyPrint ? 4 : undefined)); |
| 82 | + }); |
| 83 | +} |
0 commit comments