diff --git a/README.md b/README.md index 897e1c9..79447c7 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,33 @@ export interface FunctionExp { } ``` +## CLI Usage +The CLI can be used to parse a query or compose a previously parsed query back to SOQL. + +**Examples:** +```shell +$ npm install -g soql-parser-js +$ soql --help +$ soql --query "SELECT Id FROM Account" +$ soql -query "SELECT Id FROM Account" +$ soql -query "SELECT Id FROM Account" -output some-output-file.json +$ soql -query "SELECT Id FROM Account" -json +$ soql -query some-input-file.txt +$ soql -compose some-input-file.json +$ soql -compose some-input-file.json +$ soql -compose some-input-file.json -output some-output-file.json +``` + +**Arguments:** +``` + --query, -q A SOQL query surrounded in quotes or a file path to a text file containing a SOQL query. + --compose, -c An escaped and quoted parsed SOQL JSON string or a file path to a text file containing a parsed query JSON object. + --output, -o Filepath. + --json, -j Provide all output messages as JSON. + --debug, -d Print additional debug log messages. + --help, -h Show this help message. +``` + ## Contributing All contributions are welcome on the project. Please read the [contribution guidelines](https://github.com/paustint/soql-parser-js/blob/master/CONTRIBUTING.md). diff --git a/debug/cli.js b/debug/cli.js new file mode 100644 index 0000000..21a7080 --- /dev/null +++ b/debug/cli.js @@ -0,0 +1,4 @@ +var argv = require('minimist')(process.argv.slice(2)); + +console.log('argv:'); +console.log(JSON.stringify(argv, null, 2)); diff --git a/lib/cli.ts b/lib/cli.ts new file mode 100644 index 0000000..ebae4a5 --- /dev/null +++ b/lib/cli.ts @@ -0,0 +1,279 @@ +import * as soqlParser from '.'; +import { isString, pad } from './utils'; +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { isObject } from 'util'; + +const argv = require('minimist')(process.argv.slice(2)); + +interface Options { + query: string | undefined; + compose: string | undefined; + output: string | undefined; +} + +interface Print { + error?: boolean; + message?: string; + data?: string; + debug?: boolean; + overrideColor?: string; +} + +const debug: boolean | undefined = argv.debug || argv.d; +const printJson: boolean | undefined = argv.json || argv.j; + +log({ data: JSON.stringify(argv, null, 2) }); + +function log(options: Print) { + if (debug) { + print({ ...options, debug: true }); + } +} + +function print(options: Print) { + let color = options.error ? '31' : options.overrideColor; + if (printJson && !options.debug) { + if (isString(options.data)) { + try { + options.data = JSON.parse(options.data); + } catch (ex) {} + } + console.log(JSON.stringify(options), '\n'); + } else { + if (options.debug && options.message) { + color = color || '33'; + options.message = `[DEBUG] ${options.message}`; + console.log(`\x1b[${color}m%s\x1b[0m`, options.message); + } else if (options.message) { + color = color || '32'; + console.log(`\x1b[${color}m%s\x1b[0m`, options.message); + } + + // reset color to default + color = options.error ? '31' : options.overrideColor; + + if (options.data) { + if (isObject(options.data)) { + options.data = JSON.stringify(options.data, null, 2); + } + } + + if (options.debug && options.data) { + color = color || '33'; + options.data = `[DEBUG]\n${options.data}`; + console.log(`\x1b[${color}m%s\x1b[0m`, options.data); + } else if (options.data) { + color = color || '1'; + console.log(`\x1b[${color}m%s\x1b[0m`, options.data); + } + } +} + +function run() { + const options: Options = { + query: argv.query || argv.q, + compose: argv.compose || argv.c, + output: argv.output || argv.o, + }; + + log({ message: 'Options', data: JSON.stringify(options, null, 2) }); + + const help: boolean | undefined = argv.help || argv.h; + let validParams = false; + + if (isString(options.query)) { + log({ message: 'Parsing Query' }); + validParams = true; + parseQuery(options); + } + + if (isString(options.compose)) { + log({ message: 'Composing Query' }); + validParams = true; + composeQuery(options); + } + + if (isString(help)) { + log({ message: 'Showing explicit Help' }); + validParams = true; + printHelp(); + } + + if (!validParams) { + log({ message: 'Showing implicit Help' }); + printHelp(); + } + + process.exit(0); +} + +function parseQuery(options: Options) { + // if query starts with SELECT we know it is not a file, otherwise we will attempt to parse a file + // Check if query does not look like a query - attempt to parse file if so + let query = options.query; + log({ message: query }); + if ( + !options.query + .trim() + .toUpperCase() + .startsWith('SELECT') + ) { + log({ message: 'Query does not start with select, attempting to read file' }); + try { + if (existsSync(options.query)) { + query = readFileSync(options.query, 'utf8'); + log({ message: 'Query read from file:', data: query }); + if ( + !query + .trim() + .toUpperCase() + .startsWith('SELECT') + ) { + print({ + error: true, + message: `The query contained within the file ${ + options.query + } does not appear to be valid, please make sure the query starts with SELECT.`, + }); + process.exit(1); + } + } else { + print({ + error: true, + message: 'The query must start with SELECT or must be a valid file path to a text file containing the query.', + }); + process.exit(1); + } + } catch (ex) { + print({ + error: true, + message: `There was an error parsing the file ${ + options.query + }. Please ensure the file exists and is a text file containing a single SOQL query.`, + }); + log({ error: true, data: ex }); + process.exit(1); + } + } + + try { + const parsedQuery = soqlParser.parseQuery(query); + const queryJson = JSON.stringify(parsedQuery, null, 2); + log({ data: queryJson }); + if (options.output) { + saveOutput({ path: options.output, data: queryJson }); + } else { + print({ + message: `Parsed Query:`, + data: queryJson, + }); + } + } catch (ex) { + print({ + error: true, + message: `There was an error parsing your query`, + data: ex.message, + }); + log({ error: true, data: ex }); + process.exit(1); + } +} + +function composeQuery(options: Options) { + // if query starts with SELECT we know it is not a file, otherwise we will attempt to parse a file + // Check if query does not look like a query - attempt to parse file if so + let parsedQueryString = options.compose; + if (!options.compose.trim().startsWith('{')) { + log({ message: 'Compose is a filepath - attempting to read file' }); + try { + if (existsSync(options.compose)) { + parsedQueryString = readFileSync(options.compose, 'utf8'); + log({ + message: 'Parsed query data JSON read from file', + data: parsedQueryString, + }); + } else { + print({ + error: true, + message: `The file ${ + options.compose + } does not exist, Please provide a valid filepath or an escaped JSON string.`, + }); + process.exit(1); + } + } catch (ex) { + print({ + error: true, + message: `There was an error reading the file ${ + options.compose + }. Please ensure the file exists and is a text file containing a single parsed query JSON object.`, + }); + log({ error: true, data: ex }); + process.exit(1); + } + } + + try { + const parsedQuery = JSON.parse(parsedQueryString); + const query = soqlParser.composeQuery(parsedQuery); + if (options.output) { + log({ message: 'Attempting to save query to file' }); + saveOutput({ path: options.output, data: query }); + } else { + print({ + message: `Composed Query:`, + data: query, + }); + } + } catch (ex) { + print({ + error: true, + message: `There was an error composing your query.`, + data: ex.message, + }); + log({ error: true, data: ex }); + process.exit(1); + } +} + +function saveOutput(options: { path: string; data: string }) { + try { + print({ message: `Saving output to ${options.path}` }); + writeFileSync(options.path, options.data); + } catch (ex) { + print({ + message: `There was an error saving the file, make sure that you have access to the file location and that any directories in the path already exist.`, + data: ex.message, + }); + log({ error: true, data: ex }); + process.exit(1); + } +} + +function printHelp() { + const help = [ + { + param: '--query, -q', + message: 'A SOQL query surrounded in quotes or a file path to a text file containing a SOQL query.', + }, + { + param: '--compose, -c', + message: + 'An escaped and quoted parsed SOQL JSON string or a file path to a text file containing a parsed query JSON object.', + }, + { param: '--output, -o', message: 'Filepath.' }, + { param: '--json, -j', message: 'Provide all output messages as JSON.' }, + { param: '--debug, -d', message: 'Print additional debug log messages.' }, + { param: '--help, -h', message: 'Show this help message.' }, + ]; + print({ message: 'SOQL Parser JS CLI -- Help' }); + print({ + message: + 'To use the CLI, provide one or more of the following commands. Either one of the query or compose method are required', + }); + help.forEach(item => { + print({ overrideColor: '0', data: `${pad(item.param, 20, 4)}${item.message}` }); + }); +} + +run(); diff --git a/lib/utils.ts b/lib/utils.ts index d94ff9b..163f42a 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -39,3 +39,12 @@ export function getAsArrayStr(val: string | string[], alwaysParens: boolean = fa return alwaysParens ? `(${val || ''})` : val || ''; } } + +export function pad(val: string, len: number, left: number = 0) { + let leftPad = left > 0 ? new Array(left).fill(' ').join('') : ''; + if (val.length > len) { + return `${leftPad}${val}`; + } else { + return `${leftPad}${val}${new Array(len - val.length).fill(' ').join('')}`; + } +} diff --git a/package-lock.json b/package-lock.json index 8bf5a99..8176339 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,171 +1,9 @@ { "name": "soql-parser-js", - "version": "0.1.8", + "version": "0.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz", - "integrity": "sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.2", - "@babel/helpers": "^7.1.2", - "@babel/parser": "^7.1.2", - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2", - "convert-source-map": "^1.1.0", - "debug": "^3.1.0", - "json5": "^0.5.0", - "lodash": "^4.17.10", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz", - "integrity": "sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ==", - "dev": true, - "requires": { - "@babel/types": "^7.1.3", - "jsesc": "^2.5.1", - "lodash": "^4.17.10", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", - "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helpers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz", - "integrity": "sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==", - "dev": true, - "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2" - } - }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz", - "integrity": "sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w==", - "dev": true - }, - "@babel/template": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz", - "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.1.2", - "@babel/types": "^7.1.2" - } - }, - "@babel/traverse": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz", - "integrity": "sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.1.3", - "@babel/types": "^7.1.3", - "debug": "^3.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.10" - } - }, - "@babel/types": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz", - "integrity": "sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.10", - "to-fast-properties": "^2.0.0" - } - }, - "@comandeer/babel-plugin-banner": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@comandeer/babel-plugin-banner/-/babel-plugin-banner-4.0.0.tgz", - "integrity": "sha512-JhkNsBm8n4Z3rU1Sl2ivPX+Gd3dBcxLUdhLrn3Yok33uBGmoT0wNspXjOgToPxFqDAHHAWj83uj7MSLEJCLpxQ==", - "dev": true - }, "@gimenete/type-writer": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@gimenete/type-writer/-/type-writer-0.1.3.tgz", @@ -227,6 +65,12 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true }, + "@types/minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", + "dev": true + }, "@types/mocha": { "version": "5.2.5", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", @@ -548,12 +392,6 @@ "lodash": "^4.17.4" } }, - "babel-helper-evaluate-path": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", - "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", - "dev": true - }, "babel-helper-explode-assignable-expression": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", @@ -565,12 +403,6 @@ "babel-types": "^6.24.1" } }, - "babel-helper-flip-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", - "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", - "dev": true - }, "babel-helper-function-name": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", @@ -604,24 +436,6 @@ "babel-types": "^6.24.1" } }, - "babel-helper-is-nodes-equiv": { - "version": "0.0.1", - "resolved": "http://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", - "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", - "dev": true - }, - "babel-helper-is-void-0": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", - "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", - "dev": true - }, - "babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", - "dev": true - }, "babel-helper-optimise-call-expression": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", @@ -656,12 +470,6 @@ "babel-types": "^6.24.1" } }, - "babel-helper-remove-or-void": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", - "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", - "dev": true - }, "babel-helper-replace-supers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", @@ -676,12 +484,6 @@ "babel-types": "^6.24.1" } }, - "babel-helper-to-multiple-sequence-expressions": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", - "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", - "dev": true - }, "babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", @@ -710,98 +512,6 @@ "babel-runtime": "^6.22.0" } }, - "babel-plugin-minify-builtins": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", - "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", - "dev": true - }, - "babel-plugin-minify-constant-folding": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", - "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0" - } - }, - "babel-plugin-minify-dead-code-elimination": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.0.tgz", - "integrity": "sha512-XQteBGXlgEoAKc/BhO6oafUdT4LBa7ARi55mxoyhLHNuA+RlzRmeMAfc31pb/UqU01wBzRc36YqHQzopnkd/6Q==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-mark-eval-scopes": "^0.4.3", - "babel-helper-remove-or-void": "^0.4.3", - "lodash.some": "^4.6.0" - } - }, - "babel-plugin-minify-flip-comparisons": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", - "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", - "dev": true, - "requires": { - "babel-helper-is-void-0": "^0.4.3" - } - }, - "babel-plugin-minify-guarded-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.3.tgz", - "integrity": "sha1-zHCbRFP9IbHzAod0RMifiEJ845c=", - "dev": true, - "requires": { - "babel-helper-flip-expressions": "^0.4.3" - } - }, - "babel-plugin-minify-infinity": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", - "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", - "dev": true - }, - "babel-plugin-minify-mangle-names": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", - "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", - "dev": true, - "requires": { - "babel-helper-mark-eval-scopes": "^0.4.3" - } - }, - "babel-plugin-minify-numeric-literals": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", - "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", - "dev": true - }, - "babel-plugin-minify-replace": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", - "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", - "dev": true - }, - "babel-plugin-minify-simplify": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.0.tgz", - "integrity": "sha512-TM01J/YcKZ8XIQd1Z3nF2AdWHoDsarjtZ5fWPDksYZNsoOjQ2UO2EWm824Ym6sp127m44gPlLFiO5KFxU8pA5Q==", - "dev": true, - "requires": { - "babel-helper-flip-expressions": "^0.4.3", - "babel-helper-is-nodes-equiv": "^0.0.1", - "babel-helper-to-multiple-sequence-expressions": "^0.5.0" - } - }, - "babel-plugin-minify-type-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", - "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", - "dev": true, - "requires": { - "babel-helper-is-void-0": "^0.4.3" - } - }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", @@ -1076,39 +786,6 @@ "babel-runtime": "^6.22.0" } }, - "babel-plugin-transform-inline-consecutive-adds": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", - "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", - "dev": true - }, - "babel-plugin-transform-member-expression-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", - "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", - "dev": true - }, - "babel-plugin-transform-merge-sibling-variables": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", - "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", - "dev": true - }, - "babel-plugin-transform-minify-booleans": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", - "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", - "dev": true - }, - "babel-plugin-transform-property-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", - "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, "babel-plugin-transform-regenerator": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", @@ -1118,39 +795,6 @@ "regenerator-transform": "^0.10.0" } }, - "babel-plugin-transform-regexp-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", - "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", - "dev": true - }, - "babel-plugin-transform-remove-console": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", - "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", - "dev": true - }, - "babel-plugin-transform-remove-debugger": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", - "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", - "dev": true - }, - "babel-plugin-transform-remove-undefined": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", - "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0" - } - }, - "babel-plugin-transform-simplify-comparison-operators": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", - "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", - "dev": true - }, "babel-plugin-transform-strict-mode": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", @@ -1161,12 +805,6 @@ "babel-types": "^6.24.1" } }, - "babel-plugin-transform-undefined-to-void": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", - "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", - "dev": true - }, "babel-preset-env": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", @@ -1205,37 +843,6 @@ "semver": "^5.3.0" } }, - "babel-preset-minify": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.0.tgz", - "integrity": "sha512-xj1s9Mon+RFubH569vrGCayA9Fm2GMsCgDRm1Jb8SgctOB7KFcrVc2o8K3YHUyMz+SWP8aea75BoS8YfsXXuiA==", - "dev": true, - "requires": { - "babel-plugin-minify-builtins": "^0.5.0", - "babel-plugin-minify-constant-folding": "^0.5.0", - "babel-plugin-minify-dead-code-elimination": "^0.5.0", - "babel-plugin-minify-flip-comparisons": "^0.4.3", - "babel-plugin-minify-guarded-expressions": "^0.4.3", - "babel-plugin-minify-infinity": "^0.4.3", - "babel-plugin-minify-mangle-names": "^0.5.0", - "babel-plugin-minify-numeric-literals": "^0.4.3", - "babel-plugin-minify-replace": "^0.5.0", - "babel-plugin-minify-simplify": "^0.5.0", - "babel-plugin-minify-type-constructors": "^0.4.3", - "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", - "babel-plugin-transform-member-expression-literals": "^6.9.4", - "babel-plugin-transform-merge-sibling-variables": "^6.9.4", - "babel-plugin-transform-minify-booleans": "^6.9.4", - "babel-plugin-transform-property-literals": "^6.9.4", - "babel-plugin-transform-regexp-constructors": "^0.4.3", - "babel-plugin-transform-remove-console": "^6.9.4", - "babel-plugin-transform-remove-debugger": "^6.9.4", - "babel-plugin-transform-remove-undefined": "^0.5.0", - "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", - "babel-plugin-transform-undefined-to-void": "^6.9.4", - "lodash.isplainobject": "^4.0.6" - } - }, "babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", @@ -2276,12 +1883,6 @@ "is-obj": "^1.0.0" } }, - "dotenv": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", - "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==", - "dev": true - }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -3050,12 +2651,6 @@ "ini": "^1.3.4" } }, - "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", - "dev": true - }, "globby": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", @@ -3679,12 +3274,6 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", - "dev": true - }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -3785,18 +3374,6 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", - "dev": true - }, "lodash.template": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", @@ -3866,6 +3443,15 @@ "integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA==", "dev": true }, + "magic-string": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz", + "integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.1" + } + }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -4018,10 +3604,9 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "minimist-options": { "version": "3.0.2", @@ -4061,6 +3646,14 @@ "dev": true, "requires": { "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } } }, "mocha": { @@ -4296,6 +3889,14 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } } }, "ora": { @@ -5034,17 +4635,11 @@ "@types/node": "*" } }, - "rollup-plugin-babel-minify": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-babel-minify/-/rollup-plugin-babel-minify-6.1.1.tgz", - "integrity": "sha512-MX0lqOHp1vHd7WbHTK5OG679msgPxzGzYf4VBEg6kKptO05fgheCbN51i3EoFYSa+8/VtNDjPc23iDdZfhO2uw==", - "dev": true, - "requires": { - "@babel/core": "^7.0.0", - "@comandeer/babel-plugin-banner": "^4.0.0", - "babel-preset-minify": "^0.5.0", - "sourcemap-codec": "^1.4.3" - } + "rollup-plugin-cli": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/rollup-plugin-cli/-/rollup-plugin-cli-0.1.5.tgz", + "integrity": "sha1-lCmPLoIcdwTmioiWLS8+K4RBK7U=", + "dev": true }, "rollup-plugin-typescript2": { "version": "0.17.1", @@ -5578,12 +5173,6 @@ "tmp": "0.0.33" } }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", diff --git a/package.json b/package.json index 9414fda..09e560e 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,10 @@ "description": "Salesforce.com SOQL parser.", "main": "dist/index.js", "module": "dist/index.es.js", - "umd": "dist/index.umd.js", "types": "dist/index.d.ts", + "bin": { + "soql": "dist/cli.js" + }, "scripts": { "clean": "rm -rf ./dist/*", "test": "TS_NODE_PROJECT=\"test/tsconfig.test.json\" mocha -r ts-node/register test/**/*.spec.ts -P test/tsconfig.test.json", @@ -21,19 +23,21 @@ "author": "Austin Turner ", "license": "MIT", "dependencies": { - "antlr4ts": "0.4.1-alpha.0" + "antlr4ts": "0.4.1-alpha.0", + "minimist": "^1.2.0" }, "devDependencies": { "@types/chai": "^4.1.6", + "@types/minimist": "^1.2.0", "@types/mocha": "^5.2.5", - "@types/node": "8.0.14", + "@types/node": "^8.0.14", "antlr4ts-cli": "0.4.0-alpha.4", "chai": "^4.1.2", - "dotenv": "^6.1.0", + "magic-string": "^0.25.1", "mocha": "^5.2.0", "release-it": "^7.6.1", "rollup": "^0.66.6", - "rollup-plugin-babel-minify": "^6.1.1", + "rollup-plugin-cli": "^0.1.5", "rollup-plugin-typescript2": "^0.17.1", "ts-node": "^7.0.1", "typescript": "^2.4.1" diff --git a/rollup-plugins/add-shebang.js b/rollup-plugins/add-shebang.js new file mode 100644 index 0000000..a0f9242 --- /dev/null +++ b/rollup-plugins/add-shebang.js @@ -0,0 +1,49 @@ +import MagicString from 'magic-string'; + +/** + * Options: { + * include?: string | string[]; // output filename to include - if null and exclude is null, process all files + * exclude?: string | string[]; // output filename to exclude - if null and includes is null, process all files + * shebang?: string; // defaults to '#!/usr/bin/env node' if not provided + * } + * + */ +export default function addShebang(options = {}) { + if (options.include) { + options.include = Array.isArray(options.include) ? options.include : [options.include]; + } + if (options.exclude) { + options.exclude = Array.isArray(options.exclude) ? options.exclude : [options.exclude]; + } + options.shebang = options.shebang || '#!/usr/bin/env node'; + + function filter(fileName) { + if (options.exclude) { + if (options.exclude.find(currFileName => fileName === currFileName)) { + return false; + } + } + if (options.include) { + if (!options.include.find(currFileName => fileName === currFileName)) { + return false; + } + } + return true; + } + + return { + name: 'add-shebang', + renderChunk(code, { fileName }, { sourcemap }) { + if (!filter(fileName)) { + console.log('filtering!'); + return null; + } + let str = new MagicString(code); + str.prepend(`${options.shebang}\n`); + return { + code: str, + map: sourcemap ? str.generateMap({ hires: true }) : null, + }; + }, + }; +} diff --git a/rollup.config.js b/rollup.config.js index ce0fa9e..2e2091d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,8 +1,6 @@ import typescript from 'rollup-plugin-typescript2'; -// import minify from 'rollup-plugin-babel-minify'; import pkg from './package.json'; -import dotenv from 'dotenv'; -dotenv.config(); +import addShebang from './rollup-plugins/add-shebang'; export default [ { @@ -22,4 +20,16 @@ export default [ external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], plugins: [typescript({})], }, + { + input: 'lib/cli.ts', + output: [ + { + file: pkg.bin.soql, + format: 'cjs', + sourcemap: true, + }, + ], + external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], + plugins: [typescript({}), addShebang({ include: 'cli.js' })], + }, ]; diff --git a/test/cli.spec.ts b/test/cli.spec.ts new file mode 100644 index 0000000..e18cca4 --- /dev/null +++ b/test/cli.spec.ts @@ -0,0 +1,2 @@ +// TODO!!! +// Might need to refactor CLI to allow testing functions diff --git a/test/utils.spec.ts b/test/utils.spec.ts index 3cf5521..0c0c033 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -139,3 +139,24 @@ describe('getAsArrayStr', () => { expect(utils.getAsArrayStr(null, true)).equal(`()`); }); }); + +describe('pad', () => { + it(`Should correctly pad suffix`, () => { + const str = 'TEST'; + expect(utils.pad(str, 5)).equal(`${str} `); + expect(utils.pad(str, 5)).lengthOf(5); + expect(utils.pad(str, 100)).lengthOf(100); + }); + it(`Should correctly pad prefix`, () => { + const str = 'TEST'; + expect(utils.pad(str, 0, 2)).equal(` ${str}`); + expect(utils.pad(str, 0, 2)).lengthOf(str.length + 2); + }); + it(`Should correctly pad prefix and suffix`, () => { + const str = 'TEST'; + expect(utils.pad(str, 5, 2)).lengthOf(7); + expect(utils.pad(str, 5, 2)).equal(` ${str} `); + expect(utils.pad(str, 5, null)).lengthOf(5); + expect(utils.pad(str, 5, null)).equal(`${str} `); + }); +});