@frozenproductions/niteo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/Cargo.lock +458 -0
  2. package/Cargo.toml +13 -0
  3. package/LICENSE +21 -0
  4. package/README.md +119 -0
  5. package/bin/niteo.js +51 -0
  6. package/package.json +27 -0
  7. package/scripts/build-binary.js +23 -0
  8. package/src/app.rs +132 -0
  9. package/src/cli.rs +43 -0
  10. package/src/config.rs +989 -0
  11. package/src/discovery.rs +42 -0
  12. package/src/git.rs +63 -0
  13. package/src/main.rs +13 -0
  14. package/src/report.rs +490 -0
  15. package/src/rules/max_directory_depth.rs +125 -0
  16. package/src/rules/max_file_exports.rs +478 -0
  17. package/src/rules/max_items_per_directory.rs +145 -0
  18. package/src/rules/min_items_per_directory.rs +146 -0
  19. package/src/rules/no_barrel_files.rs +284 -0
  20. package/src/rules/no_comments.rs +222 -0
  21. package/src/rules/no_console.rs +242 -0
  22. package/src/rules/no_debugger.rs +209 -0
  23. package/src/rules/no_default_export.rs +241 -0
  24. package/src/rules/no_duplicate_file_names.rs +196 -0
  25. package/src/rules/no_empty_directories.rs +467 -0
  26. package/src/rules/no_empty_interface.rs +280 -0
  27. package/src/rules/no_enums.rs +208 -0
  28. package/src/rules/no_eval.rs +268 -0
  29. package/src/rules/no_export_star.rs +252 -0
  30. package/src/rules/no_inline_types.rs +367 -0
  31. package/src/rules/no_interface.rs +570 -0
  32. package/src/rules/no_large_file.rs +98 -0
  33. package/src/rules/no_logic_in_barrel.rs +346 -0
  34. package/src/rules/no_logic_in_domain.rs +987 -0
  35. package/src/rules/no_mutable_exports.rs +253 -0
  36. package/src/rules/no_upward_import.rs +427 -0
  37. package/src/rules/prefer_satisfies.rs +319 -0
  38. package/src/rules.rs +247 -0
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("node:child_process");
4
+ const { resolve } = require("node:path");
5
+
6
+ const packageRoot = resolve(__dirname, "..");
7
+ const result = spawnSync("cargo", ["build", "--release"], {
8
+ cwd: packageRoot,
9
+ stdio: "inherit",
10
+ });
11
+
12
+ if (result.error) {
13
+ console.error("failed to build niteo; Rust and Cargo are required for this package");
14
+ console.error(result.error.message);
15
+ process.exit(1);
16
+ }
17
+
18
+ if (result.signal) {
19
+ console.error(`niteo build terminated by signal ${result.signal}`);
20
+ process.exit(1);
21
+ }
22
+
23
+ process.exit(result.status ?? 1);
package/src/app.rs ADDED
@@ -0,0 +1,132 @@
1
+ use anyhow::Result;
2
+ use clap::Parser;
3
+ use std::env;
4
+ use std::path::{Path, PathBuf};
5
+
6
+ use crate::cli::{Cli, Command};
7
+ use crate::{config, discovery, git, report, rules};
8
+
9
+ pub fn run() -> Result<()> {
10
+ let cli = Cli::parse();
11
+ let workspace = env::current_dir()?;
12
+
13
+ match cli.command.unwrap_or(Command::Lint) {
14
+ Command::Init => create_config(&workspace),
15
+ Command::Lint => lint_workspace(
16
+ &workspace,
17
+ cli.options.root,
18
+ cli.options.scope,
19
+ cli.options.verbose,
20
+ cli.options.git,
21
+ ),
22
+ }
23
+ }
24
+
25
+ fn create_config(workspace: &Path) -> Result<()> {
26
+ let config_path = config::write_default_config(workspace)?;
27
+ println!("Created {}", config_path.display());
28
+
29
+ Ok(())
30
+ }
31
+
32
+ fn lint_workspace(
33
+ workspace: &Path,
34
+ root_override: Option<PathBuf>,
35
+ scope_override: Option<PathBuf>,
36
+ verbose: bool,
37
+ git_flag: bool,
38
+ ) -> Result<()> {
39
+ let project_config = config::ProjectConfig::resolve(workspace, root_override)?;
40
+ let scan_scope = scope_override.map(|scope| resolve_path(workspace, scope));
41
+
42
+ let files = if git_flag {
43
+ resolve_changed_files(workspace)
44
+ } else {
45
+ let changed_files = git::get_changed_typescript_files();
46
+ if !changed_files.is_empty() && git::prompt_scan_changed_files(&changed_files) {
47
+ resolve_changed_files(workspace)
48
+ } else {
49
+ discovery::discover_files(
50
+ &project_config.root,
51
+ scan_scope.as_deref(),
52
+ &project_config.gitignore,
53
+ )?
54
+ }
55
+ };
56
+
57
+ let violations = rules::check_files(
58
+ &files,
59
+ project_config.no_comments,
60
+ project_config.no_logic_in_barrel,
61
+ project_config.no_default_export,
62
+ project_config.no_export_star,
63
+ project_config.no_inline_types,
64
+ project_config.max_file_exports,
65
+ project_config.no_upward_import,
66
+ project_config.no_large_file,
67
+ project_config.no_enums,
68
+ project_config.no_barrel_files,
69
+ project_config.no_console,
70
+ project_config.no_debugger,
71
+ project_config.no_eval,
72
+ project_config.no_logic_in_domain,
73
+ project_config.no_empty_interface,
74
+ project_config.no_interface,
75
+ project_config.no_mutable_exports,
76
+ project_config.prefer_satisfies,
77
+ )?;
78
+
79
+ let mut dir_violations =
80
+ rules::check_directories(&project_config.root, project_config.no_empty_directories);
81
+
82
+ let mut name_violations =
83
+ rules::check_duplicate_file_names(&files, project_config.no_duplicate_file_names);
84
+
85
+ let mut max_items_violations = rules::check_max_items_per_directory(
86
+ &project_config.root,
87
+ project_config.max_items_per_directory,
88
+ );
89
+
90
+ let mut min_items_violations = rules::check_min_items_per_directory(
91
+ &project_config.root,
92
+ project_config.min_items_per_directory,
93
+ );
94
+
95
+ let mut depth_violations =
96
+ rules::check_max_directory_depth(&project_config.root, project_config.max_directory_depth);
97
+
98
+ let mut all_violations = violations;
99
+ all_violations.append(&mut dir_violations);
100
+ all_violations.append(&mut name_violations);
101
+ all_violations.append(&mut max_items_violations);
102
+ all_violations.append(&mut min_items_violations);
103
+ all_violations.append(&mut depth_violations);
104
+
105
+ let report = report::Report::new(files, all_violations);
106
+
107
+ println!("{}", report.render_text(verbose));
108
+
109
+ Ok(())
110
+ }
111
+
112
+ fn resolve_changed_files(workspace: &Path) -> Vec<PathBuf> {
113
+ git::get_changed_typescript_files()
114
+ .into_iter()
115
+ .map(|f: PathBuf| {
116
+ if f.is_absolute() {
117
+ f
118
+ } else {
119
+ workspace.join(f)
120
+ }
121
+ })
122
+ .filter(|f: &PathBuf| f.exists())
123
+ .collect()
124
+ }
125
+
126
+ fn resolve_path(workspace: &Path, path: PathBuf) -> PathBuf {
127
+ if path.is_absolute() {
128
+ return path;
129
+ }
130
+
131
+ workspace.join(path)
132
+ }
package/src/cli.rs ADDED
@@ -0,0 +1,43 @@
1
+ use clap::{Args, Parser, Subcommand};
2
+ use std::path::PathBuf;
3
+
4
+ #[derive(Debug, Parser)]
5
+ #[command(
6
+ name = "niteo",
7
+ version,
8
+ about = "Structural linter for TypeScript codebases"
9
+ )]
10
+ pub struct Cli {
11
+ #[command(flatten)]
12
+ pub options: CliOptions,
13
+
14
+ #[command(subcommand)]
15
+ pub command: Option<Command>,
16
+ }
17
+
18
+ #[derive(Debug, Clone, Args)]
19
+ pub struct CliOptions {
20
+ /// Override the project root to scan.
21
+ #[arg(long, global = true)]
22
+ pub root: Option<PathBuf>,
23
+
24
+ /// Restrict the scan to a path prefix.
25
+ #[arg(long, global = true)]
26
+ pub scope: Option<PathBuf>,
27
+
28
+ /// Print every violation instead of grouped, capped output.
29
+ #[arg(short, long, global = true)]
30
+ pub verbose: bool,
31
+
32
+ /// Scan only changed TypeScript files (skips prompt).
33
+ #[arg(long, global = true)]
34
+ pub git: bool,
35
+ }
36
+
37
+ #[derive(Debug, Subcommand)]
38
+ pub enum Command {
39
+ /// Generate the initial config file.
40
+ Init,
41
+ /// Scan the project for structural issues.
42
+ Lint,
43
+ }