git.delta.rocks / jrsonnet / refs/commits / b44186aaaf3a

difftreelog

chore(slop) cargo metadata

wytvqwnwYaroslav Bolyukin2026-05-05parent: #50afc8a.patch.diff
in: master

17 files changed

modifiedcmds/jrsonnet-deps/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet-deps/Cargo.toml
+++ b/cmds/jrsonnet-deps/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-deps"
-description = "List dependencies of a jsonnet file"
+description = "Command-line tool that lists imports of a jsonnet file"
+keywords = ["jsonnet", "dependencies", "cli"]
+categories = ["command-line-utilities"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcmds/jrsonnet-fmt/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/Cargo.toml
+++ b/cmds/jrsonnet-fmt/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-fmt"
-description = "Jrsonnet code formatter CLI"
+description = "Command-line jsonnet code formatter"
+keywords = ["jsonnet", "formatter", "cli"]
+categories = ["command-line-utilities", "development-tools"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcmds/jrsonnet/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet"
-description = "Rust jsonnet implementation"
+description = "Rust implementation of the jsonnet command-line interpreter"
+keywords = ["jsonnet", "json", "config", "cli"]
+categories = ["command-line-utilities", "config", "template-engine"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-cli/Cargo.toml
+++ b/crates/jrsonnet-cli/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-cli"
-description = "Utilities for building jrsonnet CLIs"
+description = "Reusable clap-based building blocks for jrsonnet command-line tools"
+keywords = ["jsonnet", "cli", "clap"]
+categories = ["command-line-interface"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -1,6 +1,9 @@
 [package]
 name = "jrsonnet-evaluator"
-description = "jsonnet interpreter"
+description = "Rust implementation of the jsonnet language interpreter"
+keywords = ["jsonnet", "interpreter", "config"]
+categories = ["compilers", "template-engine", "config"]
+readme = "README.adoc"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/import.rs
1use std::{2	any::Any,3	borrow::Cow,4	env::current_dir,5	fmt, fs,6	io::{ErrorKind, Read},7	path::{Path, PathBuf},8};910use fs::File;11use jrsonnet_gcmodule::Acyclic;12use jrsonnet_interner::IBytes;13use jrsonnet_ir::{14	IStr, SourceDefaultIgnoreJpath, SourceDirectory, SourceFifo, SourceFile, SourcePath,15};1617use crate::{18	bail,19	error::{ErrorKind::*, Result},20};21#[derive(Clone, Debug, Acyclic, Eq, Hash, PartialEq)]22pub enum ResolvePathOwned {23	Str(String),24	Path(PathBuf),25}26impl fmt::Display for ResolvePathOwned {27	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {28		match self {29			ResolvePathOwned::Str(s) => write!(f, "{s}"),30			ResolvePathOwned::Path(p) => write!(f, "{}", p.display()),31		}32	}33}34#[derive(Clone, Copy)]35pub enum ResolvePath<'s> {36	Str(&'s str),37	Path(&'s Path),38}39impl ResolvePath<'_> {40	pub fn to_owned(self) -> ResolvePathOwned {41		match self {42			ResolvePath::Str(s) => ResolvePathOwned::Str(s.to_owned()),43			ResolvePath::Path(p) => ResolvePathOwned::Path(p.to_owned()),44		}45	}46}47impl AsRef<Path> for ResolvePath<'_> {48	fn as_ref(&self) -> &Path {49		match self {50			ResolvePath::Str(s) => s.as_ref(),51			ResolvePath::Path(p) => p,52		}53	}54}55pub trait AsPathLike {56	fn as_path(&self) -> ResolvePath<'_>;57}58impl<T> AsPathLike for &T59where60	T: AsPathLike + ?Sized,61{62	fn as_path(&self) -> ResolvePath<'_> {63		(*self).as_path()64	}65}66impl AsPathLike for str {67	fn as_path(&self) -> ResolvePath<'_> {68		ResolvePath::Str(self)69	}70}71impl AsPathLike for IStr {72	fn as_path(&self) -> ResolvePath<'_> {73		ResolvePath::Str(self)74	}75}76impl AsPathLike for Cow<'_, Path> {77	fn as_path(&self) -> ResolvePath<'_> {78		ResolvePath::Path(self.as_ref())79	}80}81impl AsPathLike for Path {82	fn as_path(&self) -> ResolvePath<'_> {83		ResolvePath::Path(self)84	}85}86impl AsPathLike for ResolvePathOwned {87	fn as_path(&self) -> ResolvePath<'_> {88		match self {89			ResolvePathOwned::Str(s) => ResolvePath::Str(s),90			ResolvePathOwned::Path(path_buf) => ResolvePath::Path(path_buf),91		}92	}93}9495/// Implements file resolution logic for `import` and `importStr`96pub trait ImportResolver: Acyclic + Any {97	/// Resolves file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond98	/// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`99	/// where `${vendor}` is a library path.100	///101	/// `from` should only be returned from [`ImportResolver::resolve`], or from other defined file, any other value102	/// may result in panic103	fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {104		bail!(ImportNotSupported(from.clone(), path.as_path().to_owned()))105	}106	fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {107		self.resolve_from(&SourcePath::default(), path)108	}109110	/// Load resolved file111	/// This should only be called with value returned from [`ImportResolver::resolve_file`]/[`ImportResolver::resolve`],112	/// this cannot be resolved using associated type, as evaluator uses object instead of generic for [`ImportResolver`]113	fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>>;114}115116/// Dummy resolver, can't resolve/load any file117#[derive(Acyclic)]118pub struct DummyImportResolver;119impl ImportResolver for DummyImportResolver {120	fn load_file_contents(&self, _resolved: &SourcePath) -> Result<Vec<u8>> {121		panic!("dummy resolver can't load any file")122	}123}124#[allow(clippy::use_self)]125impl Default for Box<dyn ImportResolver> {126	fn default() -> Self {127		Box::new(DummyImportResolver)128	}129}130131/// File resolver, can load file from both FS and library paths132#[derive(Default, Acyclic)]133pub struct FileImportResolver {134	/// Library directories to search for file.135	/// Referred to as `jpath` in original jsonnet implementation.136	library_paths: Vec<PathBuf>,137}138impl FileImportResolver {139	pub fn new(library_paths: Vec<PathBuf>) -> Self {140		Self { library_paths }141	}142	/// Dynamically add new jpath, used by bindings143	pub fn add_jpath(&mut self, path: PathBuf) {144		self.library_paths.push(path);145	}146}147148/// Create `SourcePath` from path, handling directories/Fifo files (on unix)/etc149fn check_path(path: &Path) -> Result<Option<SourcePath>> {150	let meta = match fs::metadata(path) {151		Ok(v) => v,152		Err(e) if e.kind() == ErrorKind::NotFound => {153			return Ok(None);154		}155		Err(e) => bail!(ImportIo(e.to_string())),156	};157	let ty = meta.file_type();158	if ty.is_file() {159		return Ok(Some(SourcePath::new(SourceFile::new(160			path.canonicalize().map_err(|e| ImportIo(e.to_string()))?,161		))));162	}163	let ty = meta.file_type();164	#[cfg(unix)]165	{166		use std::os::unix::fs::FileTypeExt;167		if ty.is_fifo() {168			let file = fs::read(path).map_err(|e| ImportIo(format!("FIFO read failed: {e}")))?;169			return Ok(Some(SourcePath::new(SourceFifo(170				format!("{}", path.display()),171				IBytes::from(file.as_slice()),172			))));173		}174	}175	// Block device/some other magic thing.176	Err(RuntimeError("special file can't be imported".into()).into())177}178179impl ImportResolver for FileImportResolver {180	fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {181		let path = path.as_path();182		let mut direct = if let Some(f) = from.downcast_ref::<SourceFile>() {183			let mut o = f.path().to_owned();184			o.pop();185			o186		} else if let Some(d) = from.downcast_ref::<SourceDirectory>() {187			d.path().to_owned()188		} else if from.downcast_ref::<SourceDefaultIgnoreJpath>().is_some() {189			let mut direct = current_dir().map_err(|e| ImportIo(e.to_string()))?;190			direct.push(path);191			if let Some(direct) = check_path(&direct)? {192				return Ok(direct);193			}194			bail!(ImportFileNotFound(from.clone(), path.to_owned()))195		} else if from.is_default() {196			current_dir().map_err(|e| ImportIo(e.to_string()))?197		} else {198			unreachable!("resolver can't return this path")199		};200201		direct.push(path);202		if let Some(direct) = check_path(&direct)? {203			return Ok(direct);204		}205		for library_path in &self.library_paths {206			let mut cloned = library_path.clone();207			cloned.push(path);208			if let Some(cloned) = check_path(&cloned)? {209				return Ok(cloned);210			}211		}212		bail!(ImportFileNotFound(from.clone(), path.to_owned()))213	}214215	fn load_file_contents(&self, id: &SourcePath) -> Result<Vec<u8>> {216		let path = if let Some(f) = id.downcast_ref::<SourceFile>() {217			f.path()218		} else if id.downcast_ref::<SourceDirectory>().is_some() {219			bail!(ImportIsADirectory(id.clone()))220		} else if let Some(f) = id.downcast_ref::<SourceFifo>() {221			return Ok(f.1.to_vec());222		} else {223			unreachable!("other types are not supported in resolve");224		};225		let mut file = File::open(path).map_err(|_e| ResolvedFileNotFound(id.clone()))?;226		let mut out = Vec::new();227		file.read_to_end(&mut out)228			.map_err(|e| ImportIo(e.to_string()))?;229		Ok(out)230	}231232	fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {233		self.resolve_from(&SourcePath::default(), path)234	}235}
after · crates/jrsonnet-evaluator/src/import.rs
1use std::{2	any::Any,3	borrow::Cow,4	env::current_dir,5	fmt, fs,6	io::{ErrorKind, Read},7	path::{Path, PathBuf},8};910use fs::File;11use jrsonnet_gcmodule::Acyclic;12use jrsonnet_ir::{13	IStr, SourceDefaultIgnoreJpath, SourceDirectory, SourceFifo, SourceFile, SourcePath,14};1516use crate::{17	bail,18	error::{ErrorKind::*, Result},19};20#[derive(Clone, Debug, Acyclic, Eq, Hash, PartialEq)]21pub enum ResolvePathOwned {22	Str(String),23	Path(PathBuf),24}25impl fmt::Display for ResolvePathOwned {26	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {27		match self {28			ResolvePathOwned::Str(s) => write!(f, "{s}"),29			ResolvePathOwned::Path(p) => write!(f, "{}", p.display()),30		}31	}32}33#[derive(Clone, Copy)]34pub enum ResolvePath<'s> {35	Str(&'s str),36	Path(&'s Path),37}38impl ResolvePath<'_> {39	pub fn to_owned(self) -> ResolvePathOwned {40		match self {41			ResolvePath::Str(s) => ResolvePathOwned::Str(s.to_owned()),42			ResolvePath::Path(p) => ResolvePathOwned::Path(p.to_owned()),43		}44	}45}46impl AsRef<Path> for ResolvePath<'_> {47	fn as_ref(&self) -> &Path {48		match self {49			ResolvePath::Str(s) => s.as_ref(),50			ResolvePath::Path(p) => p,51		}52	}53}54pub trait AsPathLike {55	fn as_path(&self) -> ResolvePath<'_>;56}57impl<T> AsPathLike for &T58where59	T: AsPathLike + ?Sized,60{61	fn as_path(&self) -> ResolvePath<'_> {62		(*self).as_path()63	}64}65impl AsPathLike for str {66	fn as_path(&self) -> ResolvePath<'_> {67		ResolvePath::Str(self)68	}69}70impl AsPathLike for IStr {71	fn as_path(&self) -> ResolvePath<'_> {72		ResolvePath::Str(self)73	}74}75impl AsPathLike for Cow<'_, Path> {76	fn as_path(&self) -> ResolvePath<'_> {77		ResolvePath::Path(self.as_ref())78	}79}80impl AsPathLike for Path {81	fn as_path(&self) -> ResolvePath<'_> {82		ResolvePath::Path(self)83	}84}85impl AsPathLike for ResolvePathOwned {86	fn as_path(&self) -> ResolvePath<'_> {87		match self {88			ResolvePathOwned::Str(s) => ResolvePath::Str(s),89			ResolvePathOwned::Path(path_buf) => ResolvePath::Path(path_buf),90		}91	}92}9394/// Implements file resolution logic for `import` and `importStr`95pub trait ImportResolver: Acyclic + Any {96	/// Resolves file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond97	/// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`98	/// where `${vendor}` is a library path.99	///100	/// `from` should only be returned from [`ImportResolver::resolve`], or from other defined file, any other value101	/// may result in panic102	fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {103		bail!(ImportNotSupported(from.clone(), path.as_path().to_owned()))104	}105	fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {106		self.resolve_from(&SourcePath::default(), path)107	}108109	/// Load resolved file110	/// This should only be called with value returned from [`ImportResolver::resolve_file`]/[`ImportResolver::resolve`],111	/// this cannot be resolved using associated type, as evaluator uses object instead of generic for [`ImportResolver`]112	fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>>;113}114115/// Dummy resolver, can't resolve/load any file116#[derive(Acyclic)]117pub struct DummyImportResolver;118impl ImportResolver for DummyImportResolver {119	fn load_file_contents(&self, _resolved: &SourcePath) -> Result<Vec<u8>> {120		panic!("dummy resolver can't load any file")121	}122}123#[allow(clippy::use_self)]124impl Default for Box<dyn ImportResolver> {125	fn default() -> Self {126		Box::new(DummyImportResolver)127	}128}129130/// File resolver, can load file from both FS and library paths131#[derive(Default, Acyclic)]132pub struct FileImportResolver {133	/// Library directories to search for file.134	/// Referred to as `jpath` in original jsonnet implementation.135	library_paths: Vec<PathBuf>,136}137impl FileImportResolver {138	pub fn new(library_paths: Vec<PathBuf>) -> Self {139		Self { library_paths }140	}141	/// Dynamically add new jpath, used by bindings142	pub fn add_jpath(&mut self, path: PathBuf) {143		self.library_paths.push(path);144	}145}146147/// Create `SourcePath` from path, handling directories/Fifo files (on unix)/etc148fn check_path(path: &Path) -> Result<Option<SourcePath>> {149	let meta = match fs::metadata(path) {150		Ok(v) => v,151		Err(e) if e.kind() == ErrorKind::NotFound => {152			return Ok(None);153		}154		Err(e) => bail!(ImportIo(e.to_string())),155	};156	let ty = meta.file_type();157	if ty.is_file() {158		return Ok(Some(SourcePath::new(SourceFile::new(159			path.canonicalize().map_err(|e| ImportIo(e.to_string()))?,160		))));161	}162	#[cfg(unix)]163	{164		use std::os::unix::fs::FileTypeExt;165166		use jrsonnet_interner::IBytes;167168		let ty = meta.file_type();169170		if ty.is_fifo() {171			let file = fs::read(path).map_err(|e| ImportIo(format!("FIFO read failed: {e}")))?;172			return Ok(Some(SourcePath::new(SourceFifo(173				format!("{}", path.display()),174				IBytes::from(file.as_slice()),175			))));176		}177	}178	// Block device/some other magic thing.179	Err(RuntimeError("special file can't be imported".into()).into())180}181182impl ImportResolver for FileImportResolver {183	fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {184		let path = path.as_path();185		let mut direct = if let Some(f) = from.downcast_ref::<SourceFile>() {186			let mut o = f.path().to_owned();187			o.pop();188			o189		} else if let Some(d) = from.downcast_ref::<SourceDirectory>() {190			d.path().to_owned()191		} else if from.downcast_ref::<SourceDefaultIgnoreJpath>().is_some() {192			let mut direct = current_dir().map_err(|e| ImportIo(e.to_string()))?;193			direct.push(path);194			if let Some(direct) = check_path(&direct)? {195				return Ok(direct);196			}197			bail!(ImportFileNotFound(from.clone(), path.to_owned()))198		} else if from.is_default() {199			current_dir().map_err(|e| ImportIo(e.to_string()))?200		} else {201			unreachable!("resolver can't return this path")202		};203204		direct.push(path);205		if let Some(direct) = check_path(&direct)? {206			return Ok(direct);207		}208		for library_path in &self.library_paths {209			let mut cloned = library_path.clone();210			cloned.push(path);211			if let Some(cloned) = check_path(&cloned)? {212				return Ok(cloned);213			}214		}215		bail!(ImportFileNotFound(from.clone(), path.to_owned()))216	}217218	fn load_file_contents(&self, id: &SourcePath) -> Result<Vec<u8>> {219		let path = if let Some(f) = id.downcast_ref::<SourceFile>() {220			f.path()221		} else if id.downcast_ref::<SourceDirectory>().is_some() {222			bail!(ImportIsADirectory(id.clone()))223		} else if let Some(f) = id.downcast_ref::<SourceFifo>() {224			return Ok(f.1.to_vec());225		} else {226			unreachable!("other types are not supported in resolve");227		};228		let mut file = File::open(path).map_err(|_e| ResolvedFileNotFound(id.clone()))?;229		let mut out = Vec::new();230		file.read_to_end(&mut out)231			.map_err(|e| ImportIo(e.to_string()))?;232		Ok(out)233	}234235	fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {236		self.resolve_from(&SourcePath::default(), path)237	}238}
modifiedcrates/jrsonnet-formatter/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-formatter/Cargo.toml
+++ b/crates/jrsonnet-formatter/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-formatter"
-description = "Jrsonnet code formatter"
+description = "Jsonnet source code formatter library"
+keywords = ["jsonnet", "formatter"]
+categories = ["development-tools"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-interner/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-interner/Cargo.toml
+++ b/crates/jrsonnet-interner/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-interner"
-description = "Jrsonnet string interning"
+description = "String interner used by jrsonnet"
+keywords = ["jsonnet", "interner", "string"]
+categories = ["data-structures", "memory-management"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-ir-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/Cargo.toml
+++ b/crates/jrsonnet-ir-parser/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-ir-parser"
-description = "Jrsonnet hand-rolled parser which parses source directly into IR"
+description = "Hand-rolled recursive-descent parser that produces jrsonnet IR directly"
+keywords = ["jsonnet", "parser"]
+categories = ["parser-implementations"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-ir/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-ir/Cargo.toml
+++ b/crates/jrsonnet-ir/Cargo.toml
@@ -1,6 +1,9 @@
 [package]
 name = "jrsonnet-ir"
-description = "jsonnet language parser and AST"
+description = "Intermediate representation for the jsonnet language used by jrsonnet"
+keywords = ["jsonnet", "ir", "ast"]
+categories = ["compilers"]
+readme = "README.adoc"
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-lexer/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-lexer/Cargo.toml
+++ b/crates/jrsonnet-lexer/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-lexer"
-description = "Jrsonnet lexer shared between rowan and hand-rolled parser"
+description = "Jsonnet lexer shared between the rowan-based and hand-rolled jrsonnet parsers"
+keywords = ["jsonnet", "lexer"]
+categories = ["parser-implementations"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-macros/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-macros/Cargo.toml
+++ b/crates/jrsonnet-macros/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-macros"
-description = "Macros to reduce boilerplate in jrsonnet-evaluator usage"
+description = "Procedural macros to reduce boilerplate in jrsonnet-evaluator usage"
+keywords = ["jsonnet", "macros"]
+categories = ["development-tools::procedural-macro-helpers"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-peg-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/Cargo.toml
+++ b/crates/jrsonnet-peg-parser/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-peg-parser"
-description = "Legacy peg-based parser for jrsonnet"
+description = "Legacy PEG-based parser producing jrsonnet IR"
+keywords = ["jsonnet", "parser", "peg"]
+categories = ["parser-implementations"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-rowan-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/Cargo.toml
+++ b/crates/jrsonnet-rowan-parser/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-rowan-parser"
-description = "Rowan-based CST for jrsonnet"
+description = "Rowan-based concrete syntax tree parser for jsonnet, suitable for tooling and LSP"
+keywords = ["jsonnet", "parser", "rowan", "cst"]
+categories = ["parser-implementations"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-rowan-parser/src/ast.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/ast.rs
+++ b/crates/jrsonnet-rowan-parser/src/ast.rs
@@ -77,9 +77,6 @@
 
 	use super::{AstChildren, AstNode, AstToken, SyntaxKind, SyntaxNode, SyntaxToken};
 
-	pub fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> {
-		parent.children().find_map(N::cast)
-	}
 	pub fn token_child<N: AstToken>(parent: &SyntaxNode) -> Option<N> {
 		parent.children_with_tokens().find_map(|n| match n {
 			rowan::NodeOrToken::Node(_) => None,
modifiedcrates/jrsonnet-stdlib/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/Cargo.toml
+++ b/crates/jrsonnet-stdlib/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-stdlib"
-description = "jsonnet standard library packaged as crate"
+description = "Jsonnet standard library implementation for jrsonnet"
+keywords = ["jsonnet", "stdlib"]
+categories = ["template-engine"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
modifiedcrates/jrsonnet-types/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-types/Cargo.toml
+++ b/crates/jrsonnet-types/Cargo.toml
@@ -1,6 +1,8 @@
 [package]
 name = "jrsonnet-types"
-description = "Jrsonnet type system definition"
+description = "Type system definitions used by jrsonnet"
+keywords = ["jsonnet", "types"]
+categories = ["data-structures"]
 authors.workspace = true
 edition.workspace = true
 license.workspace = true