From 840f346d2a80641fd59772b8bbe10313ea8391aa Mon Sep 17 00:00:00 2001 From: Maxwell Huang-Hobbs Date: Wed, 13 Nov 2024 21:16:39 +0000 Subject: [PATCH] update schemas, cargo udeps fixes --- Cargo.lock | 58 +++++++++++++++++++ Cargo.toml | 1 + crates/repo-schemas/Cargo.toml | 21 +++++++ crates/repo-schemas/src/lib.rs | 2 + crates/repo-schemas/src/schemas_up_to_date.rs | 42 ++++++++++++++ crates/unused_finder/Cargo.toml | 1 + crates/unused_finder/src/cfg/mod.rs | 3 +- schemas/unused-config.schema.json | 57 ++++++++++++++++++ 8 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 crates/repo-schemas/Cargo.toml create mode 100644 crates/repo-schemas/src/lib.rs create mode 100644 crates/repo-schemas/src/schemas_up_to_date.rs create mode 100644 schemas/unused-config.schema.json diff --git a/Cargo.lock b/Cargo.lock index dade41f3..23e98cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,6 +596,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.13.0" @@ -1654,6 +1660,22 @@ dependencies = [ name = "repo-root" version = "0.2.0-beta.1" +[[package]] +name = "repo-schemas" +version = "0.0.0" +dependencies = [ + "dockerfile-parser", + "path-slash", + "pretty_assertions", + "regex", + "repo-root", + "schemars", + "serde-hjson", + "serde_json", + "toml", + "unused_finder", +] + [[package]] name = "rstack" version = "0.3.3" @@ -1737,6 +1759,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.72", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1803,6 +1849,17 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "serde_json" version = "1.0.122" @@ -2682,6 +2739,7 @@ dependencies = [ "pathdiff", "pretty_assertions", "rayon", + "schemars", "serde", "serde_json", "stringreader", diff --git a/Cargo.toml b/Cargo.toml index fbad44f1..c3db70d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ swc_ecma_parser = "0.149.0" swc_ecma_transforms = "0.238.0" swc_ecma_visit = "0.104.6" thiserror = "1.0.52" +schemars = "0.8.21" [profile.release] diff --git a/crates/repo-schemas/Cargo.toml b/crates/repo-schemas/Cargo.toml new file mode 100644 index 00000000..794fa057 --- /dev/null +++ b/crates/repo-schemas/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "repo-schemas" +version = "0.0.0" +authors = ["Maxwell Huang-Hobbs "] +license = "Apache-2.0" +description = """ +Crate for introspective tests on this repo's schemas +""" +edition = "2018" + +[dev-dependencies] +dockerfile-parser = "0.8.0" +path-slash.workspace = true +pretty_assertions.workspace = true +regex.workspace = true +repo-root = { path = "../repo-root" } +serde-hjson = { version = "1.1.0", features = [] } +toml = "0.8.19" +schemars.workspace = true +serde_json.workspace = true +unused_finder = { version = "0.2.0", path = "../unused_finder" } diff --git a/crates/repo-schemas/src/lib.rs b/crates/repo-schemas/src/lib.rs new file mode 100644 index 00000000..ded08beb --- /dev/null +++ b/crates/repo-schemas/src/lib.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +mod schemas_up_to_date; diff --git a/crates/repo-schemas/src/schemas_up_to_date.rs b/crates/repo-schemas/src/schemas_up_to_date.rs new file mode 100644 index 00000000..6870449a --- /dev/null +++ b/crates/repo-schemas/src/schemas_up_to_date.rs @@ -0,0 +1,42 @@ +use path_slash::PathBufExt; +use schemars::schema_for; +use std::path::{Path, PathBuf}; +use unused_finder::UnusedFinderJSONConfig; + +fn enforce_schema(file_path: &Path, schema: &schemars::schema::RootSchema) { + // Check if the file exists + if !file_path.exists() { + // Just write the intended schema + let schema_str = serde_json::to_string_pretty(schema).unwrap(); + std::fs::create_dir_all(file_path.parent().unwrap()).unwrap(); + std::fs::write(file_path, schema_str).unwrap(); + } else { + // read the schmea from the file + let file_str = std::fs::read_to_string(file_path).unwrap(); + let file_schema: schemars::schema::RootSchema = serde_json::from_str(&file_str).unwrap(); + + if file_schema != *schema { + // overwrite with the intended schema if the original is out of date + let schema_str = serde_json::to_string_pretty(schema).unwrap(); + std::fs::write(file_path, schema_str).unwrap(); + + // fail the test with a pretty_eq comparison + panic!( + "schema mismatch for {:?}. The schema file has been updated with the intended comments, which you should commit", + file_path + ); + } + } +} + +#[test] +fn test_unused_config_schema() { + let repo_root = repo_root::find_git_root(); + let schemadir_path = repo_root.join(PathBuf::from_slash("schemas/")); + + // Check unused-config.schema.json + enforce_schema( + &schemadir_path.join("unused-config.schema.json"), + &schema_for!(UnusedFinderJSONConfig), + ); +} diff --git a/crates/unused_finder/Cargo.toml b/crates/unused_finder/Cargo.toml index a93a4f08..50eac41b 100644 --- a/crates/unused_finder/Cargo.toml +++ b/crates/unused_finder/Cargo.toml @@ -37,6 +37,7 @@ ignore = "0.4.23" abspath = { version = "0.2.0", path = "../abspath" } itertools = "0.13.0" debug_print = "1.0.0" +schemars.workspace = true [dev-dependencies] stringreader = "0.1.1" diff --git a/crates/unused_finder/src/cfg/mod.rs b/crates/unused_finder/src/cfg/mod.rs index 408c1fa8..15b7d593 100644 --- a/crates/unused_finder/src/cfg/mod.rs +++ b/crates/unused_finder/src/cfg/mod.rs @@ -3,6 +3,7 @@ use std::fmt::{Display, Formatter}; use itertools::Itertools; use package_match_rules::PackageMatchRules; use rayon::iter::Either; +use schemars::JsonSchema; use serde::Deserialize; pub mod package_match_rules; @@ -62,7 +63,7 @@ pub enum ConfigError { /// /// This struct is used to deserialize the UnusedFinderConfig struct /// from a config file to with serde / over the debug bridge for napi -#[derive(Debug, Default, Clone, Deserialize)] +#[derive(Debug, Default, Clone, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct UnusedFinderJSONConfig { /// Path to the root directory of the repository. diff --git a/schemas/unused-config.schema.json b/schemas/unused-config.schema.json new file mode 100644 index 00000000..bd1e07b2 --- /dev/null +++ b/schemas/unused-config.schema.json @@ -0,0 +1,57 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "UnusedFinderJSONConfig", + "description": "A JSON serializable proxy for the UnusedFinderConfig struct\n\nThis struct is used to deserialize the UnusedFinderConfig struct from a config file to with serde / over the debug bridge for napi", + "type": "object", + "required": [ + "entryPackages", + "rootPaths" + ], + "properties": { + "allowUnusedTypes": { + "description": "If true, type-only exports will not be reported as used. However, the transitive dependencies of unused types will still be reported as unused.", + "default": false, + "type": "boolean" + }, + "entryPackages": { + "description": "List of packages that should be considered \"entry\" packages All transitive imports from the exposed exports of these packages will be considered used\n\nNote that the only files that are considered roots are the ones that are _explicitly exported_, either as an entry in the package's \"exports\" config, or as a main/module export\n\nItems are parsed in one of three ways: 1. If the item starts with \"./\", it is treated as a path glob, and evaluated against the paths of package folders, relative to the repo root. 2. If the item contains any of \"~)('!*\", it is treated as a name-glob, and evaluated as a glob against the names of packages. 3. Otherwise, the item is treated as the name of an individual package, and matched literally.", + "type": "array", + "items": { + "type": "string" + } + }, + "repoRoot": { + "description": "Path to the root directory of the repository.", + "default": "", + "type": "string" + }, + "reportExportedSymbols": { + "description": "If true, individual exported symbols are also tracked", + "default": false, + "type": "boolean" + }, + "rootPaths": { + "description": "Root paths to walk as source files\n\nThese can be either absolute paths, or paths relative to the repo root", + "type": "array", + "items": { + "type": "string" + } + }, + "skip": { + "description": "A List of globs. Matching files and directories won't be scanned during the file walk\n\nMatches are made against the names of the individual directories, NOT the full directory paths", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "testFiles": { + "description": "List of glob patterns to mark as \"tests\". These files will be marked as used, and all of their transitive dependencies will also be marked as used\n\nglob patterns are matched against the relative file path from the root of the repository", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } +} \ No newline at end of file