chore(release): prepare public source release

This commit is contained in:
MercuryToolbox Release
2026-07-18 15:41:59 +08:00
commit e365e5df4d
508 changed files with 163373 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
[package]
name = "jsonlgrep"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
authors.workspace = true
readme.workspace = true
publish.workspace = true
description = "Filter JSONL and line-oriented streams with AI-friendly output."
keywords.workspace = true
categories.workspace = true
[lints]
workspace = true
[dependencies]
common = { path = "../common", default-features = false }
lexopt.workspace = true
regex-lite.workspace = true
serde.workspace = true
serde_json.workspace = true
[dev-dependencies]
assert_cmd.workspace = true
predicates.workspace = true
tempfile.workspace = true
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
//! Binary entry point for `jsonlgrep`.
fn main() {
std::process::exit(jsonlgrep::main_entry());
}
+256
View File
@@ -0,0 +1,256 @@
//! Integration tests for the `jsonlgrep` command.
use std::path::PathBuf;
use assert_cmd::Command;
use jsonlgrep::{Query, parse_query};
use predicates::prelude::*;
fn cargo_command() -> Command {
Command::cargo_bin("jsonlgrep").expect("binary")
}
fn cargo_binary() -> PathBuf {
assert_cmd::cargo::cargo_bin("jsonlgrep")
}
fn powershell_command(script: String) -> Command {
let mut command = Command::new("pwsh");
command.args(["-NoProfile", "-Command"]).arg(script);
command
}
fn ps_quote(value: impl std::fmt::Display) -> String {
format!("'{}'", value.to_string().replace('\'', "''"))
}
fn fixture(path: &str) -> PathBuf {
let fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("..")
.join("fixtures")
.join(path);
assert!(
fixture.exists(),
"missing fixture `{path}` at {}",
fixture.display()
);
fixture
}
#[test]
fn parses_field_queries() {
assert_eq!(
parse_query("level=error").expect("exact query"),
Query::FieldEquals {
field: "level".into(),
value: "error".into(),
}
);
assert!(matches!(
parse_query("msg~=fail").expect("regex query"),
Query::FieldRegex { field, .. } if field == "msg"
));
assert_eq!(
parse_query("panic").expect("text query"),
Query::Contains("panic".into())
);
assert!(matches!(
parse_query("level!=info").expect("negative exact query"),
Query::FieldNotEquals { field, value } if field == "level" && value == "info"
));
assert!(matches!(
parse_query("msg!~=login").expect("negative regex query"),
Query::FieldNotRegex { field, .. } if field == "msg"
));
}
#[test]
fn filters_and_projects_jsonl_records() {
cargo_command()
.arg("level=error")
.arg(fixture("jsonl/events.jsonl"))
.arg("--pick")
.arg("ts,msg")
.assert()
.success()
.stdout(predicate::str::contains(
"ts=2026-04-20T12:01:00Z msg=failed login",
));
}
#[test]
fn text_and_json_projections_survive_conditional_raw_retention() {
let temp = tempfile::tempdir().expect("tempdir");
let path = temp.path().join("spaced.jsonl");
std::fs::write(
&path,
"{ \"level\" : \"error\" , \"msg\" : \"failed login\" , \"ts\" : \"2026-04-20T12:01:00Z\" }\n",
)
.expect("fixture");
let mut text = cargo_command();
text.arg("level=error")
.arg(&path)
.arg("--pick")
.arg("ts,msg")
.assert()
.success()
.stdout("ts=2026-04-20T12:01:00Z msg=failed login\n");
let mut json = cargo_command();
json.arg("level=error")
.arg(&path)
.arg("--pick")
.arg("ts,msg")
.arg("--json")
.assert()
.success()
.stdout(predicate::str::contains("\"ts\":\"2026-04-20T12:01:00Z\""))
.stdout(predicate::str::contains("\"msg\":\"failed login\""));
}
#[test]
fn counts_matches_as_json() {
cargo_command()
.arg("msg~=login")
.arg(fixture("jsonl/events.jsonl"))
.arg("--count")
.arg("--json")
.assert()
.success()
.stdout("{\"count\":2}\n");
}
#[test]
fn supports_powershell_pipeline() {
let binary = cargo_binary();
let input = fixture("jsonl/events.jsonl");
let script = format!(
"[System.IO.File]::ReadLines({}) | & {} 'level=warn'",
ps_quote(input.display()),
ps_quote(binary.display())
);
powershell_command(script)
.assert()
.success()
.stdout(predicate::str::contains("cache warmup"));
}
#[test]
fn filters_nested_fields_and_negative_predicates() {
let temp = tempfile::tempdir().expect("tempdir");
let path = temp.path().join("nested.jsonl");
std::fs::write(
&path,
concat!(
"{\"event\":{\"user\":{\"name\":\"alice\"}},\"status\":500,\"ok\":false}\n",
"{\"event\":{\"user\":{\"name\":\"bob\"}},\"status\":200,\"ok\":true}\n",
"{\"event\":{\"user\":{\"name\":\"carol\"}},\"status\":404,\"ok\":false}\n"
),
)
.expect("fixture");
let mut nested = cargo_command();
nested
.arg("event.user.name=alice")
.arg(&path)
.arg("--pick")
.arg("event.user.name,status")
.assert()
.success()
.stdout(predicate::str::contains("event.user.name=alice status=500"));
let mut negative_exact = cargo_command();
negative_exact
.arg("status!=200")
.arg(&path)
.arg("--pick")
.arg("event.user.name,status")
.assert()
.success()
.stdout(predicate::str::contains("alice"))
.stdout(predicate::str::contains("carol"))
.stdout(predicate::str::contains("bob").not());
let mut negative_regex = cargo_command();
negative_regex
.arg("event.user.name!~=^(alice|bob)$")
.arg(&path)
.arg("--pick")
.arg("event.user.name")
.assert()
.success()
.stdout("event.user.name=carol\n");
}
#[test]
fn help_includes_examples_for_nested_and_powershell_usage() {
cargo_command()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("event.user.name=alice"))
.stdout(predicate::str::contains("field!=value"))
.stdout(predicate::str::contains("ConvertFrom-Json"))
.stdout(predicate::str::contains("--toon"));
}
#[test]
fn mistyped_regex_operator_reports_the_fix() {
let error = parse_query("level~warn|error").expect_err("missing equals should fail");
assert!(
error
.to_string()
.contains("did you mean 'level~=warn|error'"),
"unexpected query error: {error}"
);
cargo_command()
.arg("level~warn|error")
.arg(fixture("jsonl/events.jsonl"))
.assert()
.failure()
.stderr(predicate::str::contains("did you mean 'level~=warn|error'"));
}
#[test]
fn stops_after_limit_before_parsing_invalid_trailing_jsonl() {
let temp = tempfile::tempdir().expect("tempdir");
let path = temp.path().join("limited.jsonl");
std::fs::write(
&path,
concat!(
"{\"level\":\"error\",\"msg\":\"first\"}\n",
"{not valid json}\n",
"{\"level\":\"error\",\"msg\":\"third\"}\n"
),
)
.expect("fixture");
cargo_command()
.arg("level=error")
.arg(&path)
.arg("--input-format")
.arg("jsonl")
.arg("--count")
.arg("--limit")
.arg("1")
.assert()
.success()
.stdout("1\n");
}
#[test]
fn rejects_zero_limit() {
cargo_command()
.arg("level=error")
.arg(fixture("jsonl/events.jsonl"))
.arg("--limit")
.arg("0")
.assert()
.failure()
.code(2)
.stderr(predicate::str::contains("--limit must be greater than 0"));
}