Skip to content

Commit dae9ce5

Browse files
authored
Merge pull request #64 from codingtools/cdt-63
Add to_csv support for Avro command
2 parents dbd62fd + ec340b8 commit dae9ce5

17 files changed

+154
-45
lines changed

.gitignore

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ node_modules
99
/.idea
1010
cdt.iml
1111
**/.DS_Store
12-
output/*
13-
!output/.gitkeep
12+
13+
output
14+
output/**.json
15+
output/**.avro
16+
output/**.avsc
17+
1418
coverage/*.json
19+
20+

README.md

+9-11
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,11 @@ USAGE
161161
$ cdt hash [STRING]
162162
163163
OPTIONS
164-
-f, --file=file file to be hashed
165-
-h, --help show CLI help
166-
-o, --outputFile=outputFile output file path
167-
-s, --string=string string to be hashed
168-
-t, --type=type type of hash [SHA1(default), MD5, SHA256, SHA512, RMD160 or RIPEMD160]
164+
-f, --file=file file to be hashed
165+
-h, --help show CLI help
166+
-o, --output=output output file path
167+
-s, --string=string string to be hashed
168+
-t, --type=type type of hash [SHA1(default), MD5, SHA256, SHA512, RMD160 or RIPEMD160]
169169
```
170170

171171
_See code: [src/commands/hash.ts](https://github.com/codingtools/cdt/blob/v0.1.6/src/commands/hash.ts)_
@@ -196,12 +196,10 @@ USAGE
196196
$ cdt minify [FILE]
197197
198198
OPTIONS
199-
-f, --file=file file to be minified
200-
-h, --help show CLI help
201-
-o, --outputFile=outputFile output file path
202-
203-
-t, --type=type type of file to be minified, it will try to find type with extension supported: JS,
204-
HTML/HTM, CSS
199+
-f, --file=file file to be minified
200+
-h, --help show CLI help
201+
-o, --output=output output file path
202+
-t, --type=type type of file to be minified, it will try to find type with extension supported: JS, HTML/HTM, CSS
205203
```
206204

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

oclif.manifest.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":"0.1.6","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"},"output":{"name":"output","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"},"output":{"name":"output","type":"option","char":"o","description":"output file path"}},"args":[{"name":"file"}]}}}

package-lock.json

+28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"detect-character-encoding": "^0.8.0",
2525
"encoding-japanese": "^1.0.30",
2626
"jshashes": "^1.0.7",
27+
"json-2-csv": "^3.5.9",
2728
"minify": "^5.0.0",
2829
"moment": "^2.24.0",
2930
"moment-timezone": "^0.5.27",

src/commands/avro.ts

+56-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Command, flags} from '@oclif/command'
22
import * as avro from 'avsc'
33
import * as chalk from 'chalk'
44
import * as fs from 'fs' // includes all from avro-js and some more
5+
import * as Json2Csv from 'json-2-csv'
56

67
import Logger from '../utilities/logger'
78
import Utilities from '../utilities/utilities'
@@ -12,9 +13,10 @@ export default class Avro extends Command {
1213
static GET_SCHEMA = 'get_schema'
1314
static TO_JSON = 'to_json'
1415
static TO_AVRO = 'to_avro'
16+
static TO_CSV = 'to_csv'
1517

1618
// do not change order otherwise we need to change order in getCommand() also
17-
static SupportedCommands = [Avro.GET_SCHEMA, Avro.TO_JSON, Avro.TO_AVRO]
19+
static SupportedCommands = [Avro.GET_SCHEMA, Avro.TO_JSON, Avro.TO_AVRO, Avro.TO_CSV]
1820
static flags = {
1921
help: flags.help({char: 'h'}),
2022
file: flags.string({char: 'f' , description: 'input file path'}),
@@ -52,12 +54,14 @@ export default class Avro extends Command {
5254

5355
private executeCommand(flags: any, args: any) {
5456
switch (args.command) {
55-
case Avro.SupportedCommands[0]:
57+
case Avro.GET_SCHEMA:
5658
return this.getSchema(flags, args)
57-
case Avro.SupportedCommands[1]:
59+
case Avro.TO_JSON:
5860
return this.toJson(flags, args)
59-
case Avro.SupportedCommands[2]:
61+
case Avro.TO_AVRO:
6062
return this.toAvro(flags, args)
63+
case Avro.TO_CSV:
64+
return this.toCsv(flags, args)
6165
default:
6266
Logger.error(this, 'Unsupported Command, supported: ' + Avro.SupportedCommands)
6367
}
@@ -83,19 +87,55 @@ export default class Avro extends Command {
8387

8488
// tslint:disable-next-line:no-unused
8589
private toJson(flags: any, args: any) {
90+
Logger.progressStart(this, 'Converting Avro To Json')
91+
// setTimeout(() => {
92+
Logger.progressStop(this, ' Converting Avro To Json')
8693
Utilities.truncateFile(this, flags.output)
8794
avro.createFileDecoder(flags.file)
8895
.on('data', function (recordStr) {
8996
// @ts-ignore
9097
Utilities.appendStringToFile(this, flags.output, JSON.stringify(recordStr))
9198
})
9299
Logger.success(this, `${chalk.blue('Json')} written to file: ${chalk.green(flags.output)}`) // this will output error and exit command
100+
// }, 1000)
101+
}
102+
103+
// tslint:disable-next-line:no-unused
104+
private toCsv(flags: any, args: any) {
105+
Logger.progressStart(this, 'Converting Avro To Csv')
106+
107+
// setTimeout(() => {
108+
Logger.progressStop(this, ' Converting Avro To Csv')
109+
Utilities.truncateFile(this, flags.output)
110+
let prependHeader = true // only write on the first line
111+
avro.createFileDecoder(flags.file)
112+
.on('data', function (recordStr) {
113+
// @ts-ignore
114+
let json = JSON.parse(JSON.stringify(recordStr))
115+
Json2Csv.json2csv(json, (err?: Error, csv?: string) => {
116+
if (csv) {
117+
// @ts-ignore
118+
Utilities.appendStringToFile(this, flags.output, csv + '\n')
119+
}
120+
if (err) {
121+
// @ts-ignore
122+
Logger.error(this, err.toString())
123+
}
124+
}, {prependHeader})
125+
prependHeader = false
126+
})
127+
Logger.success(this, `${chalk.blue('Csv')} written to file: ${chalk.green(flags.output)}`) // this will output error and exit command
128+
// }, 300)
93129
}
94130

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

135+
Logger.progressStart(this, 'Generating Avro')
136+
// setTimeout(() => {
137+
Logger.progressStop(this, ' Generating Avro')
138+
99139
let schema = avro.parse(flags.schemaType)
100140
let avroEncoder = new avro.streams.BlockEncoder(schema)
101141

@@ -104,9 +144,9 @@ export default class Avro extends Command {
104144
// We write the records to the block encoder, which will take care of serializing them
105145
// into an object container file.
106146

107-
let jsonStr = '[' + Utilities.getInputString(this, flags, args) + ']'
108-
jsonStr = jsonStr.replace(/[\s\n]+/mg, '')
109-
jsonStr = jsonStr.replace(/\}\{/mg, '},{')
147+
let inputString = Utilities.getInputString(this, flags, args)
148+
let jsonStr = this.convertAvroJsonToValidJson(inputString)
149+
110150
let jsonObjects = JSON.parse(jsonStr)
111151

112152
jsonObjects.forEach(function (data: any) {
@@ -119,5 +159,14 @@ export default class Avro extends Command {
119159
})
120160
Logger.success(this, `${chalk.blue('Avro')} written to file: ${chalk.green(flags.output)}`) // this will output error and exit command
121161
avroEncoder.end()
162+
// }, 300)
163+
164+
}
165+
166+
private convertAvroJsonToValidJson(json: string) {
167+
let jsonStr = '[' + json + ']'
168+
jsonStr = jsonStr.replace(/[\s\n]+/mg, '')
169+
jsonStr = jsonStr.replace(/\}\{/mg, '},{')
170+
return jsonStr
122171
}
123172
}

src/commands/bundlephobia.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,6 @@ export default class Bundlephobia extends Command {
2222

2323
static args = [{name: 'package'}] // only one can be passed club which one passed through flag and arg
2424

25-
private static getErrorMessage(pkg: string, message: string) {
26-
// replacing will be useful when we do not have specific version
27-
// output will be like below
28-
/*
29-
⚠ @codingtools/[email protected] This package has not been published with this particular version.
30-
Valid versions - `<code>latest</code>`, `<code>0.1.1</code>` and `<code>0.1.2</code>`
31-
*/
32-
if (message.includes('This package has not been published with this particular version.'))
33-
message = message.replace(/`<code>|<\/code>`/g, '')
34-
35-
return `${chalk.red(pkg)} ${message}`
36-
}
37-
3825
private static getSize(byteSize: number) {
3926
if (byteSize >= 1024 * 1024)
4027
return `${chalk.red((byteSize / (1024 * 1024)).toFixed(1) + 'MB')}`
@@ -55,6 +42,19 @@ export default class Bundlephobia extends Command {
5542
this.bundlePhobia(flags, args)
5643
}
5744

45+
private getErrorMessage(pkg: string, message: string) {
46+
// replacing will be useful when we do not have specific version
47+
// output will be like below
48+
/*
49+
⚠ @codingtools/[email protected] This package has not been published with this particular version.
50+
Valid versions - `<code>latest</code>`, `<code>0.1.1</code>` and `<code>0.1.2</code>`
51+
*/
52+
if (message.includes('This package has not been published with this particular version.'))
53+
message = message.replace(/`<code>|<\/code>`/g, '')
54+
55+
return `${chalk.red(pkg)} ${message}`
56+
}
57+
5858
private getPackages(flags: any, args: any) {
5959
let packages = []
6060

@@ -104,7 +104,7 @@ export default class Bundlephobia extends Command {
104104
dependencyCount += successResponse.data.dependencyCount
105105
Logger.progressStop(this, this.getSuccessMessage(successResponse.data))
106106
}).catch(errorResponse => {
107-
Logger.progressStopError(this, Bundlephobia.getErrorMessage(packageInfo.pkg, errorResponse.response.data.error.message))
107+
Logger.progressStopError(this, this.getErrorMessage(packageInfo.pkg, errorResponse.response.data.error.message))
108108
})
109109
// tslint:disable-next-line:no-unused
110110
}))

src/utilities/utilities.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ export default class Utilities {
6161
}
6262

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

test/commands/avro.test.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {expect, test} from '@oclif/test'
2+
import {readFileSync} from 'fs'
23

34
describe('avro', () => {
45
//todo if file is invalid
@@ -49,6 +50,8 @@ describe('avro', () => {
4950
expect(ctx.stdout).to.contain('Schema file is not provided')
5051
})
5152

53+
54+
// TODO: BUG this is just skipping test , find a way to implement wait() etc.
5255
test
5356
.stdout()
5457
.command(['avro', '-f', 'test/resources/avro/person.avro', 'get_schema'])
@@ -58,19 +61,24 @@ describe('avro', () => {
5861
, 5000) // wait for it to write stuff on console
5962
})
6063

61-
6264
test
6365
.stdout()
64-
.command(['avro', '-f', 'test/resources/avro/person.avro', '-o', 'test/resources/avro/output/person.json','to_json'])
65-
.it('if to_json commands run with success', ctx => {
66+
.command(['avro', '-f', 'test/resources/avro/twitter.json', '-o', 'test/resources/avro/output/twitter.avro', '-t', 'test/resources/avro/twitter.avsc', 'to_avro'])
67+
.it('if to_avro commands run with success', ctx => {
6668
expect(ctx.stdout).to.contain('success')
6769
})
6870

6971
test
70-
.timeout(20000) // added timeout to resolve timeout problem
7172
.stdout()
72-
.command(['avro', '-f', 'test/resources/avro/person.json', '-o', 'test/resources/avro/output/person.avro', '-t', 'test/resources/avro/person.avsc', 'to_avro'])
73-
.it('if to_avro commands run with success', ctx => {
73+
.command(['avro', '-f', 'test/resources/avro/person.avro', '-o', 'test/resources/avro/output/person.json','to_json'])
74+
.it('if to_json commands run with success', ctx => {
7475
expect(ctx.stdout).to.contain('success')
7576
})
7677
})
78+
79+
test
80+
.stdout()
81+
.command(['avro', '-f', 'test/resources/avro/person.avro', '-o', 'test/resources/avro/output/person.csv','to_csv'])
82+
.it('if to_csv commands run with success', ctx => {
83+
expect(ctx.stdout).to.contain('success')
84+
})
-158 KB
Binary file not shown.

test/resources/avro/output/person.json

-1
This file was deleted.

test/resources/avro/twitter.avro

465 Bytes
Binary file not shown.

test/resources/avro/twitter.avsc

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"type" : "record",
3+
"name" : "twitter_schema",
4+
"namespace" : "com.miguno.avro",
5+
"fields" : [ {
6+
"name" : "username",
7+
"type" : "string",
8+
"doc" : "Name of the user account on Twitter.com"
9+
}, {
10+
"name" : "tweet",
11+
"type" : "string",
12+
"doc" : "The content of the user's Twitter message"
13+
}, {
14+
"name" : "timestamp",
15+
"type" : "long",
16+
"doc" : "Unix epoch time in seconds"
17+
} ],
18+
"doc:" : "A basic schema for storing Twitter messages"
19+
}

test/resources/avro/twitter.json

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"username":"miguno","tweet":"Rock: Nerf paper, scissors is fine.","timestamp": 1366150681 }
2+
{"username":"BlizzardCS","tweet":"Works as intended. Terran is IMBA.","timestamp": 1366154481 }

test/resources/output/ouput.css

-1
This file was deleted.

test/resources/output/out.txt

-1
This file was deleted.

0 commit comments

Comments
 (0)