ji
ji
is a JSON Inspector for the command line.
Input
ji handles its input much like grep
. Data can be passed to it through stdin
or by providing a list of filenames. Globbing works.
The Reader class reads from the standard input or a list of files, and emits events when a JSON document is read, and when it's finished reading documents.
require 'events'fs = require 'fs'querystring = require 'querystring'
Read the standard input, by resuming the standard input stream and calling
@readStream
on it.
: -> processstdinsetEncoding 'utf8' processstdinresume @readStream '(standard input)'processstdin=> @emit 'end'
Read the next file from the @filenames
array which contains the remaining
files to be read.
: filename = @_filenamesshift if filename stream = fscreateReadStream filename streamsetEncoding 'utf8' @readStream filenamestream=> @_readNextFile else @emit 'end'
Read a list of files. Makes a copy of the filenames so it can be modified without modifying the value passed in by reference.
: @_filenames = filenamesslice @_readNextFile
Read data from a stream. At present only one document per stream is permitted.
: data = '' streamon 'data' data += chunk streamon 'end'=> document = JSONparsedata @emit 'data'namedocument
Selecting Nodes
JSON Pointer is used for selecting nodes. It uses the same syntax as URLs. This differs from the spec in that you're allowed to omit the leading slash ('/').
To decode, split a string on slashes and unescape each component.
: querystringunescapecomponent for component in pathsplit '/'
To encode, escape each component and join it with a slash.
: escaped = querystringescapecomponent for component in components escapedjoin '/'
Get a value at a jsonpointer path.
: value = document components = Pointerdecode path for component in components if typeof value == 'object' and value != null value = valuecomponent else value = undefined value
Printing Data
: str = JSONstringify datanull2 consolelog str
Gluing It Together
A Program class interprets the command-line arguments and runs commands.
Construct the object instances.
: -> @reader = @printer = @buildOptions
The options are specified here. The key is both the key that will be set on the Program instance and the default long option name. A boolean option won't use a parameter; all other options will.
options: path: short: 'p' #replace: # short: 'r' #flat: # short: 'f' # boolean: true
Build the options into a more searchable format.
: -> @_options = for nameoption of @options option.name = name option.long or= name @_optionsoptionlong= option @_optionsoptionshort= option if optionshort
Parse the arguments using the options table. Make a lookup table for short options.
: args = argvslice2 @filenames = i = 0 while i < argslength if /^-/testargsi option = @_optionsargsi1 @exitWithError 'unrecognized option: ' + argsiunless option if optionboolean @optionname= true else if typeof argsi+1== 'undefined' @exitWithError 'value required for option ' + argsi @optionname= argsi+1 i += 1 else @filenamespush argsi i += 1
Parse the options and execute the command.
: -> @parse processargv @readeron 'data' value = document if @path value = Pointerget document@path @printerprint value unless typeof value == 'undefined' if @filenameslength > 0 @readerreadFiles @filenames else @readerreadStandardInput
Display errors.
: consoleerror 'error: ' + message : @showError message processexit 1
Run the program, unless this is being imported from another module.
unless moduleparent program = programrun
Export the classes.
exports.Reader = Readerexports.Pointer = Pointerexports.Printer = Printerexports.Program = Program