#!/usr/bin/env perl
use
lib
"$FindBin::Bin/../lib"
;
my
$decoder
;
my
$decoder_module
;
my
$decoder_debug
= 0;
my
$decoder_choice
;
for
(
my
$i
= 0;
$i
<
@ARGV
;
$i
++) {
if
(
$ARGV
[
$i
] eq
'--debug'
) {
$decoder_debug
= 1;
splice
@ARGV
,
$i
, 1;
redo
;
}
if
(
$ARGV
[
$i
] eq
'--use'
) {
$decoder_choice
=
$ARGV
[
$i
+ 1];
splice
@ARGV
,
$i
, 2;
redo
;
}
}
if
(
$decoder_choice
) {
if
(
$decoder_choice
eq
'JSON::MaybeXS'
) {
$decoder
= \
&JSON::MaybeXS::decode_json
;
$decoder_module
=
'JSON::MaybeXS'
;
}
elsif
(
$decoder_choice
eq
'Cpanel::JSON::XS'
) {
$decoder
= \
&Cpanel::JSON::XS::decode_json
;
$decoder_module
=
'Cpanel::JSON::XS'
;
}
elsif
(
$decoder_choice
eq
'JSON::XS'
) {
$decoder
= \
&JSON::XS::decode_json
;
$decoder_module
=
'JSON::XS'
;
}
elsif
(
$decoder_choice
eq
'JSON::PP'
) {
$decoder
= \
&JSON::PP::decode_json
;
$decoder_module
=
'JSON::PP'
;
}
else
{
die
"[ERROR] Unknown JSON module: $decoder_choice\n"
;
}
}
else
{
$decoder
= \
&JSON::MaybeXS::decode_json
;
$decoder_module
=
'JSON::MaybeXS'
;
}
$decoder
= \
&Cpanel::JSON::XS::decode_json
;
$decoder_module
=
'Cpanel::JSON::XS'
;
}
$decoder
= \
&JSON::XS::decode_json
;
$decoder_module
=
'JSON::XS'
;
}
else
{
$decoder
= \
&JSON::PP::decode_json
;
$decoder_module
=
'JSON::PP'
;
}
}
warn
"[DEBUG] Using $decoder_module\n"
if
$decoder_debug
;
if
(!
@ARGV
) {
print
<<'USAGE';
jq-lite - A lightweight jq-like JSON query tool written in pure Perl
Usage:
jq-lite [options] '.query' [file.json]
Options:
-r, --raw-output Print raw strings instead of JSON-encoded values
--color Colorize JSON output (keys, strings, numbers, booleans)
--use <Module> Force JSON decoder module (e.g. JSON::PP, JSON::XS, Cpanel::JSON::XS)
--debug Show which JSON module is being used
-h, --help Show this help message
-v, --version Show version information
Examples:
cat users.json | jq-lite '.users[].name'
jq-lite '.users[] | select(.age > 25)' users.json
jq-lite -r '.users[] | .name' users.json
jq-lite '.meta has "version"' config.json
jq-lite --color '.items | sort | reverse | first' data.json
Homepage:
USAGE
exit
0;
}
my
$raw_output
= 0;
my
$color_output
= 0;
my
$query
;
my
$filename
;
while
(
@ARGV
) {
my
$arg
=
shift
@ARGV
;
if
(
$arg
eq
'--raw-output'
||
$arg
eq
'-r'
) {
$raw_output
= 1;
}
elsif
(
$arg
eq
'--color'
) {
$color_output
= 1;
}
elsif
(
$arg
eq
'--help'
||
$arg
eq
'-h'
) {
print
<<'USAGE';
jq-lite - A lightweight jq-like JSON query tool written in pure Perl
Usage:
jq-lite [options] '.query' [file.json]
Options:
-r, --raw-output Print raw strings instead of JSON-encoded values
--color Colorize JSON output (keys, strings, numbers, booleans)
--use <Module> Force JSON decoder module (e.g. JSON::PP, JSON::XS, Cpanel::JSON::XS)
--debug Show which JSON module is being used
-h, --help Show this help message
-v, --version Show version information
Examples:
cat users.json | jq-lite '.users[].name'
jq-lite '.users[] | select(.age > 25)' users.json
jq-lite -r '.users[] | .name' users.json
jq-lite '.meta has "version"' config.json
jq-lite --color '.items | sort | reverse | first' data.json
Homepage:
USAGE
exit
0;
}
elsif
(
$arg
eq
'--version'
||
$arg
eq
'-v'
) {
print
"jq-lite version $JQ::Lite::VERSION\n"
;
exit
0;
}
elsif
(!
defined
$filename
&& -f
$arg
) {
$filename
=
$arg
;
}
elsif
(!
defined
$query
) {
$query
=
$arg
;
}
elsif
(!
defined
$filename
&& -f
$arg
) {
$filename
=
$arg
;
}
else
{
die
"Usage: jq-lite [options] '.query' [file.json]\n"
;
}
}
my
$json_text
;
if
(
defined
$filename
) {
open
my
$fh
,
'<'
,
$filename
or
die
"Cannot open file '$filename': $!\n"
;
local
$/;
$json_text
= <
$fh
>;
close
$fh
;
}
else
{
local
$/;
$json_text
= <STDIN>;
}
my
$jq
= JQ::Lite->new(
raw
=>
$raw_output
);
sub
colorize_json {
my
$json
=
shift
;
$json
=~ s/
"([^"
]+)
"(?=\s*:)/color("
cyan
")."
\
"$1\""
.color(
"reset"
)/ge;
$json
=~ s/:
"([^"
]*)
"/"
:
".color("
green
")."
\
"$1\""
.color(
"reset"
)/ge;
$json
=~ s/: (\d+(\.\d+)?)/
": "
.color(
"yellow"
).
"$1"
.color(
"reset"
)/ge;
$json
=~ s/: (true|false|null)/
": "
.color(
"magenta"
).
"$1"
.color(
"reset"
)/ge;
return
$json
;
}
sub
print_results {
my
@results
=
@_
;
my
$pp
= JSON::PP->new->utf8->canonical->pretty;
for
my
$r
(
@results
) {
if
(!
defined
$r
) {
print
"null\n"
;
}
elsif
(
$raw_output
&& !
ref
(
$r
)) {
print
"$r\n"
;
}
else
{
my
$json
=
$pp
->encode(
$r
);
$json
= colorize_json(
$json
)
if
$color_output
;
print
$json
;
}
}
}
if
(!
defined
$query
) {
system
(
"stty -icanon -echo"
);
$SIG
{INT} =
sub
{
system
(
"stty sane"
);
print
"\n[EXIT]\n"
;
exit
0;
};
my
$input
=
''
;
my
@last_results
;
my
$ok
=
eval
{
@last_results
=
$jq
->run_query(
$json_text
,
'.'
);
1;
};
if
(!
$ok
|| !
@last_results
) {
my
$data
=
eval
{ JSON::PP->new->decode(
$json_text
) };
if
(
$data
) {
@last_results
= (
$data
);
}
}
system
(
"clear"
);
if
(
@last_results
) {
print_results(
@last_results
);
}
else
{
print
"[INFO] Failed to load initial JSON data.\n"
;
}
print
"\nType query (ESC to quit):\n"
;
print
"> $input\n"
;
while
(1) {
my
$char
;
sysread
(STDIN,
$char
, 1);
my
$ord
=
ord
(
$char
);
last
if
$ord
== 27;
if
(
$ord
== 127 ||
$char
eq
"\b"
) {
chop
$input
if
length
(
$input
);
}
else
{
$input
.=
$char
;
}
system
(
"clear"
);
my
@results
;
my
$ok
=
eval
{
@results
=
$jq
->run_query(
$json_text
,
$input
);
1;
};
if
(
$ok
&&
@results
) {
@last_results
=
@results
;
}
if
(!
$ok
) {
print
"[INFO] Invalid or partial query. Showing last valid results.\n"
;
}
elsif
(!
@results
) {
print
"[INFO] Query returned no results. Showing last valid results.\n"
;
}
if
(
@last_results
) {
eval
{
print_results(
@last_results
);
1;
} or
do
{
my
$e
= $@ ||
'Unknown error'
;
print
"[ERROR] Failed to print: $e\n"
;
};
}
else
{
print
"[INFO] No previous valid results.\n"
;
}
print
"\n> $input\n"
;
}
system
(
"stty sane"
);
print
"\nGoodbye.\n"
;
exit
0;
}
my
@results
=
eval
{
$jq
->run_query(
$json_text
,
$query
) };
if
($@) {
die
"[ERROR] Invalid query: $@\n"
;
}
if
(!
@results
) {
warn
"[INFO] No results returned for query.\n"
;
exit
1;
}
print_results(
@results
);