Skip to content

Feature/avro support #51 #53

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ $ npm install -g @codingtools/cdt
$ cdt COMMAND
running command...
$ cdt (-v|--version|version)
@codingtools/cdt/0.1.5 darwin-x64 node-v12.9.0
@codingtools/cdt/0.1.6 darwin-x64 node-v12.9.0
$ cdt --help [COMMAND]
USAGE
$ cdt COMMAND
Expand All @@ -49,6 +49,7 @@ USAGE
# Commands
<!-- commands -->
* [`cdt autocomplete [SHELL]`](#cdt-autocomplete-shell)
* [`cdt avro [COMMAND]`](#cdt-avro-command)
* [`cdt bundlephobia [PACKAGE]`](#cdt-bundlephobia-package)
* [`cdt crypto [STRING]`](#cdt-crypto-string)
* [`cdt datetime [DATE]`](#cdt-datetime-date)
Expand Down Expand Up @@ -79,6 +80,23 @@ EXAMPLES

_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v0.1.4/src/commands/autocomplete/index.ts)_

## `cdt avro [COMMAND]`

Avro Utility command

```
USAGE
$ cdt avro [COMMAND]

OPTIONS
-f, --file=file input file path
-h, --help show CLI help
-o, --output=output output file path
-t, --schemaType=schemaType schema type file path
```

_See code: [src/commands/avro.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/avro.ts)_

## `cdt bundlephobia [PACKAGE]`

Find cost of adding a npm/yarn packages or all dependencies in package.json file
Expand All @@ -93,7 +111,7 @@ OPTIONS
-p, --packages=packages packages for which cost is required, can pass more than one separated by space
```

_See code: [src/commands/bundlephobia.ts](https://github.com/codingtools/cdt/blob/v0.1.5/src/commands/bundlephobia.ts)_
_See code: [src/commands/bundlephobia.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/bundlephobia.ts)_

## `cdt crypto [STRING]`

Expand All @@ -113,7 +131,7 @@ OPTIONS
-s, --string=string string to be encrypted/decrypted
```

_See code: [src/commands/crypto.ts](https://github.com/codingtools/cdt/blob/v0.1.5/src/commands/crypto.ts)_
_See code: [src/commands/crypto.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/crypto.ts)_

## `cdt datetime [DATE]`

Expand All @@ -131,7 +149,7 @@ OPTIONS
-z, --timezone=timezone Timezone for Datetime parsing, default: Your timezone
```

_See code: [src/commands/datetime.ts](https://github.com/codingtools/cdt/blob/v0.1.5/src/commands/datetime.ts)_
_See code: [src/commands/datetime.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/datetime.ts)_

## `cdt hash [STRING]`

Expand All @@ -149,7 +167,7 @@ OPTIONS
-t, --type=type type of hash [SHA1(default), MD5, SHA256, SHA512, RMD160 or RIPEMD160]
```

_See code: [src/commands/hash.ts](https://github.com/codingtools/cdt/blob/v0.1.5/src/commands/hash.ts)_
_See code: [src/commands/hash.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/hash.ts)_

## `cdt help [COMMAND]`

Expand Down Expand Up @@ -185,9 +203,16 @@ OPTIONS
HTML/HTM, CSS
```

_See code: [src/commands/minify.ts](https://github.com/codingtools/cdt/blob/v0.1.5/src/commands/minify.ts)_
_See code: [src/commands/minify.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/minify.ts)_
<!-- commandsstop -->

## Acknowledgement
* this cli uses following opensource libraries/services
* [bundlephobia](https://bundlephobia.com/)
* [avro-js](https://openbase.io/js/avro-js)
* [avsc](https://github.com/mtth/avsc)

And many others, great thanks to all the people involved in developnment and support :)

## Contribution

Expand All @@ -199,6 +224,18 @@ Please feel free to provide any suggestion for new utility in [Issues](https://g

This Project is created and supported by [Ashish Patel](http://ashish.live/)

## Releasing Version
* this needs to be done from release* branch
```bash
npm version patch
```
it will update readme.md and update package.json, also will create tag and commit.

```bash
npm publish --access public
```
this will publish package to **npm**

## License

[MIT](https://raw.githubusercontent.com/codingtools/cdt/master/LICENSE)
Empty file added my.json
Empty file.
1 change: 1 addition & 0 deletions oclif.manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"0.1.5","commands":{"avro":{"id":"avro","description":"Avro Utility command","pluginName":"@codingtools/cdt","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"file":{"name":"file","type":"option","char":"f","description":"input file path"},"output":{"name":"output","type":"option","char":"o","description":"output file path"},"schemaType":{"name":"schemaType","type":"option","char":"t","description":"schema type file path"}},"args":[{"name":"command"}]},"bundlephobia":{"id":"bundlephobia","description":"Find cost of adding a npm/yarn packages or all dependencies in package.json file","pluginName":"@codingtools/cdt","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"packages":{"name":"packages","type":"option","char":"p","description":"packages for which cost is required, can pass more than one separated by space"},"file":{"name":"file","type":"option","char":"f","description":"path for package.json file"}},"args":[{"name":"package"}]},"crypto":{"id":"crypto","description":"Encryption and Decryption functionality for File/String","pluginName":"@codingtools/cdt","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"encryption":{"name":"encryption","type":"option","char":"e","description":"encryption type, Supported [AES, DES, 3DES, Rabbit, RC4, RC4Drop]"},"decryption":{"name":"decryption","type":"option","char":"d","description":"decryption type, Supported [AES, DES, 3DES, Rabbit, RC4, RC4Drop]"},"string":{"name":"string","type":"option","char":"s","description":"string to be encrypted/decrypted"},"file":{"name":"file","type":"option","char":"f","description":"file to be encrypted/decrypted"},"key":{"name":"key","type":"option","char":"k","description":"key for encryption/decryption"},"mode":{"name":"mode","type":"option","char":"m","description":"Block Mode, Supported [CBC, CFB, CTR, OFB, ECB]"}},"args":[{"name":"string"}]},"datetime":{"id":"datetime","description":"Date and Time utility","pluginName":"@codingtools/cdt","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"date":{"name":"date","type":"option","char":"d","description":"Datetime input string, default: Current Datetime, could also be passed through argument"},"format":{"name":"format","type":"option","char":"f","description":"Datetime format, default: Do MMMM YYYY, h:m:s A, Z UTC"},"timezone":{"name":"timezone","type":"option","char":"z","description":"Timezone for Datetime parsing, default: Your timezone"},"locale":{"name":"locale","type":"option","char":"l","description":"Locale, default: en"}},"args":[{"name":"date"}]},"hash":{"id":"hash","description":"Hashing functionality for a string/file","pluginName":"@codingtools/cdt","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"type":{"name":"type","type":"option","char":"t","description":"type of hash [SHA1(default), MD5, SHA256, SHA512, RMD160 or RIPEMD160]"},"string":{"name":"string","type":"option","char":"s","description":"string to be hashed"},"file":{"name":"file","type":"option","char":"f","description":"file to be hashed"},"outputFile":{"name":"outputFile","type":"option","char":"o","description":"output file path"}},"args":[{"name":"string"}]},"minify":{"id":"minify","description":"File Minifier","pluginName":"@codingtools/cdt","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"type":{"name":"type","type":"option","char":"t","description":"type of file to be minified, it will try to find type with extension supported: JS, HTML/HTM, CSS"},"file":{"name":"file","type":"option","char":"f","description":"file to be minified"},"outputFile":{"name":"outputFile","type":"option","char":"o","description":"output file path"}},"args":[{"name":"file"}]}}}
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@codingtools/cdt",
"description": "CLI for Developers",
"version": "0.1.5",
"version": "0.1.6",
"author": "Ashish Patel @ashishpatel0720",
"bin": {
"cdt": "./bin/run"
Expand All @@ -16,6 +16,7 @@
"@oclif/plugin-help": "^2.2.1",
"@oclif/plugin-not-found": "^1.2.3",
"@oclif/plugin-warn-if-update-available": "^1.7.0",
"avsc": "^5.4.18",
"axios": "^0.19.0",
"chalk": "^3.0.0",
"crypto-js": "^3.1.9-1",
Expand Down Expand Up @@ -76,7 +77,7 @@
"@oclif/plugin-autocomplete"
],
"warn-if-update-available": {
"timeoutInDays": 1,
"timeoutInDays": 7,
"message": "<%= chalk.blue(config.name) %> update available from <%= chalk.greenBright(config.version) %> to <%= chalk.greenBright(latest) %>."
}
},
Expand Down
123 changes: 123 additions & 0 deletions src/commands/avro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {Command, flags} from '@oclif/command'
import * as avro from 'avsc'
import * as chalk from 'chalk'
import * as fs from 'fs' // includes all from avro-js and some more

import Logger from '../utilities/logger'
import Utilities from '../utilities/utilities'

export default class Avro extends Command {
static description = 'Avro Utility command'

static GET_SCHEMA = 'get_schema'
static TO_JSON = 'to_json'
static TO_AVRO = 'to_avro'

// do not change order otherwise we need to change order in getCommand() also
static SupportedCommands = [Avro.GET_SCHEMA, Avro.TO_JSON, Avro.TO_AVRO]
static flags = {
help: flags.help({char: 'h'}),
file: flags.string({char: 'f' , description: 'input file path'}),
output: flags.string({char: 'o' , description: 'output file path'}),
schemaType: flags.string({char: 't' , description: 'schema type file path'}),

}

static args = [{name: 'command'}] // operation type
/*
* input,output, and operation are all must
* */
async run() {
const {args, flags} = this.parse(Avro)

this.checkParameters(flags, args)
this.executeCommand(flags, args)
}

// to check required parameters passed or not
private checkParameters(flags: any, args: any) {
if (!flags.file)
Logger.error(this, 'Input file is not provided')
if (!args.command)
Logger.error(this, 'Command is empty or not provided, supported:' + Avro.SupportedCommands)

// if exists then make it upperCase
args.command = args.command.toLowerCase()

// output is not mendatory for 'get_schema' command
if (args.command !== Avro.GET_SCHEMA && !flags.output)
Logger.error(this, 'Output file is not provided')

}

private executeCommand(flags: any, args: any) {
switch (args.command) {
case Avro.SupportedCommands[0]:
return this.getSchema(flags, args)
case Avro.SupportedCommands[1]:
return this.toJson(flags, args)
case Avro.SupportedCommands[2]:
return this.toAvro(flags, args)
default:
Logger.error(this, 'Unsupported Command, supported: ' + Avro.SupportedCommands)
}
}

// tslint:disable-next-line:no-unused
private getSchema(flags: any, args: any) {
avro.createFileDecoder(flags.file)
.on('metadata', function (type) {
let output = type.schema()
let schemaStr = JSON.stringify(output)
if (flags.output) {
// @ts-ignore
Utilities.writeStringToFile(this, flags.output, schemaStr)
} else {
// @ts-ignore
Logger.success(this,
`${chalk.yellow('Avro Schema')}\n${JSON.stringify(output, null, ' ')}`
)
}
})
}

// tslint:disable-next-line:no-unused
private toJson(flags: any, args: any) {
Utilities.truncateFile(this, flags.output)
avro.createFileDecoder(flags.file)
.on('data', function (recordStr) {
// @ts-ignore
Utilities.appendStringToFile(this, flags.output, JSON.stringify(recordStr))
})
Logger.success(this, `${chalk.blue('Json')} written to file: ${chalk.green(flags.output)}`) // this will output error and exit command
}

private toAvro(flags: any, args: any) {
if (!flags.schemaType)
Logger.error(this, 'Schema file is not provided')

let schema = avro.parse(flags.schemaType)
let avroEncoder = new avro.streams.BlockEncoder(schema)

avroEncoder.pipe(fs.createWriteStream(flags.output))

// We write the records to the block encoder, which will take care of serializing them
// into an object container file.

let jsonStr = '[' + Utilities.getInputString(this, flags, args) + ']'
jsonStr = jsonStr.replace(/[\s\n]+/mg, '')
jsonStr = jsonStr.replace(/\}\{/mg, '},{')
let jsonObjects = JSON.parse(jsonStr)

jsonObjects.forEach(function (data: any) {
if (schema.isValid(data)) {
avroEncoder.write(data)
} else {
// @ts-ignore
Logger.warn(this, `${chalk.yellow('[SKIPPING RECORD]')} schema is invalid: ${chalk.yellowBright(JSON.stringify(data))}`)
}
})
Logger.success(this, `${chalk.blue('Avro')} written to file: ${chalk.green(flags.output)}`) // this will output error and exit command
avroEncoder.end()
}
}
1 change: 0 additions & 1 deletion src/commands/bundlephobia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Logger from '../utilities/logger'
import Utilities from '../utilities/utilities'

// TODO:
// ADD package.json support
// ADD VALID tests ( for now they just ignoring )
export default class Bundlephobia extends Command {
static description = 'Find cost of adding a npm/yarn packages or all dependencies in package.json file'
Expand Down
27 changes: 21 additions & 6 deletions src/utilities/utilities.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// tslint:disable-next-line:file-name-casing
import {Command} from '@oclif/command'
import * as chalk from 'chalk'
import * as fs from 'fs'

import Logger from './logger'
// tslint:disable-next-line:no-unnecessary-class
export default class Utilities {
public static getStringFromFile(thisRef: any, filePath: string) {
public static getStringFromFile(thisRef: Command, filePath: string) {
let fileStr = ''
if (!fs.existsSync(filePath)) {
Logger.error(thisRef, `Could not find file: ${chalk.red(filePath)}`) // this will output error and exit command
Expand All @@ -15,7 +16,7 @@ export default class Utilities {
}
return fileStr
}
public static getJsonObjectFromFile(thisRef: any, filePath: string) {
public static getJsonObjectFromFile(thisRef: Command, filePath: string) {
if (!fs.existsSync(filePath)) {
Logger.error(thisRef, `Could not find file: ${chalk.red(filePath)}`) // this will output error and exit command
} else {
Expand All @@ -28,26 +29,40 @@ export default class Utilities {
}
}

public static getInputString(thisRef: any , flags: any, args: any) { //need to make it static so Crypto can use this
public static getInputString(thisRef: Command , flags: any, args: any) { //need to make it static so Crypto can use this
// if -s or -f is not passed we will take it from args
if (flags.string) //if -s given
return flags.string
else if (flags.file) {
else if (flags.file) { // if -f given
Logger.info(thisRef, `reading file: ${chalk.green(flags.file)}`)
return Utilities.getStringFromFile(thisRef, flags.file)
} else
return args.string
}

public static writeStringToFile(thisRef: any, filePath: string, string: string) {
public static writeStringToFile(thisRef: Command, filePath: string, string: string) {
if (!fs.existsSync(filePath))
Logger.info(thisRef, `Could not find file: ${chalk.yellow(filePath + ', creating new one')}`) // this will output error and exit command
else
Logger.warn(thisRef, `File already exists: ${chalk.green(filePath)}, ${chalk.yellow('overriding content')}`) // this will output error and exit command

fs.writeFileSync(filePath, string)
Logger.success(thisRef, `output written to file: ${chalk.green(filePath)}`) // this will output error and exit command

if (string !== '') // this condition comes for truncating
Logger.success(thisRef, `output written to file: ${chalk.green(filePath)}`) // this will output error and exit command
// return `${chalk.red(pkg)} ${message}`

}

public static appendStringToFile(thisRef: Command, filePath: string, string: string) {
if (!fs.existsSync(filePath))
Logger.info(thisRef, `Could not find file: ${chalk.yellow(filePath + ', creating new one')}`) // this will output error and exit command
fs.appendFileSync(filePath, string)
}

public static truncateFile(thisRef: Command, filePath: string) {
if (fs.existsSync(filePath))
Logger.info(thisRef, `file found: ${chalk.yellow(filePath + ', truncating')}`) // this will output error and exit command
Utilities.writeStringToFile(thisRef, filePath, '') // write nothing
}
}
Loading