@owenlamont/ryl 0.4.1

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 (217) hide show
  1. package/.github/CODEOWNERS +1 -0
  2. package/.github/dependabot.yml +13 -0
  3. package/.github/workflows/ci.yml +107 -0
  4. package/.github/workflows/release.yml +613 -0
  5. package/.github/workflows/update_dependencies.yml +61 -0
  6. package/.github/workflows/update_linters.yml +56 -0
  7. package/.pre-commit-config.yaml +87 -0
  8. package/.yamllint +4 -0
  9. package/AGENTS.md +200 -0
  10. package/Cargo.lock +908 -0
  11. package/Cargo.toml +32 -0
  12. package/LICENSE +21 -0
  13. package/README.md +230 -0
  14. package/bin/ryl.js +1 -0
  15. package/clippy.toml +1 -0
  16. package/docs/config-presets.md +100 -0
  17. package/img/benchmark-5x5-5runs.svg +2176 -0
  18. package/package.json +28 -0
  19. package/pyproject.toml +42 -0
  20. package/ruff.toml +107 -0
  21. package/rumdl.toml +20 -0
  22. package/rust-toolchain.toml +3 -0
  23. package/rustfmt.toml +3 -0
  24. package/scripts/benchmark_perf_vs_yamllint.py +400 -0
  25. package/scripts/coverage-missing.ps1 +80 -0
  26. package/scripts/coverage-missing.sh +60 -0
  27. package/src/bin/discover_config_bin.rs +24 -0
  28. package/src/cli_support.rs +33 -0
  29. package/src/conf/mod.rs +85 -0
  30. package/src/config.rs +2099 -0
  31. package/src/decoder.rs +326 -0
  32. package/src/discover.rs +31 -0
  33. package/src/lib.rs +19 -0
  34. package/src/lint.rs +558 -0
  35. package/src/main.rs +535 -0
  36. package/src/migrate.rs +233 -0
  37. package/src/rules/anchors.rs +517 -0
  38. package/src/rules/braces.rs +77 -0
  39. package/src/rules/brackets.rs +77 -0
  40. package/src/rules/colons.rs +475 -0
  41. package/src/rules/commas.rs +372 -0
  42. package/src/rules/comments.rs +299 -0
  43. package/src/rules/comments_indentation.rs +243 -0
  44. package/src/rules/document_end.rs +175 -0
  45. package/src/rules/document_start.rs +84 -0
  46. package/src/rules/empty_lines.rs +152 -0
  47. package/src/rules/empty_values.rs +255 -0
  48. package/src/rules/float_values.rs +259 -0
  49. package/src/rules/flow_collection.rs +562 -0
  50. package/src/rules/hyphens.rs +104 -0
  51. package/src/rules/indentation.rs +803 -0
  52. package/src/rules/key_duplicates.rs +218 -0
  53. package/src/rules/key_ordering.rs +303 -0
  54. package/src/rules/line_length.rs +326 -0
  55. package/src/rules/mod.rs +25 -0
  56. package/src/rules/new_line_at_end_of_file.rs +23 -0
  57. package/src/rules/new_lines.rs +95 -0
  58. package/src/rules/octal_values.rs +121 -0
  59. package/src/rules/quoted_strings.rs +577 -0
  60. package/src/rules/span_utils.rs +37 -0
  61. package/src/rules/trailing_spaces.rs +65 -0
  62. package/src/rules/truthy.rs +420 -0
  63. package/tests/brackets_carriage_return.rs +114 -0
  64. package/tests/build_global_cfg_error.rs +23 -0
  65. package/tests/cli_anchors_rule.rs +143 -0
  66. package/tests/cli_braces_rule.rs +104 -0
  67. package/tests/cli_brackets_rule.rs +104 -0
  68. package/tests/cli_colons_rule.rs +65 -0
  69. package/tests/cli_commas_rule.rs +104 -0
  70. package/tests/cli_comments_indentation_rule.rs +61 -0
  71. package/tests/cli_comments_rule.rs +67 -0
  72. package/tests/cli_config_data_error.rs +30 -0
  73. package/tests/cli_config_flags.rs +66 -0
  74. package/tests/cli_config_migrate.rs +229 -0
  75. package/tests/cli_document_end_rule.rs +92 -0
  76. package/tests/cli_document_start_rule.rs +92 -0
  77. package/tests/cli_empty_lines_rule.rs +87 -0
  78. package/tests/cli_empty_values_rule.rs +68 -0
  79. package/tests/cli_env_config.rs +34 -0
  80. package/tests/cli_exit_and_errors.rs +41 -0
  81. package/tests/cli_file_encoding.rs +203 -0
  82. package/tests/cli_float_values_rule.rs +64 -0
  83. package/tests/cli_format_options.rs +316 -0
  84. package/tests/cli_global_cfg_relaxed.rs +20 -0
  85. package/tests/cli_hyphens_rule.rs +104 -0
  86. package/tests/cli_indentation_rule.rs +65 -0
  87. package/tests/cli_invalid_project_config.rs +39 -0
  88. package/tests/cli_key_duplicates_rule.rs +104 -0
  89. package/tests/cli_key_ordering_rule.rs +59 -0
  90. package/tests/cli_line_length_rule.rs +85 -0
  91. package/tests/cli_list_files.rs +29 -0
  92. package/tests/cli_new_line_rule.rs +141 -0
  93. package/tests/cli_new_lines_rule.rs +119 -0
  94. package/tests/cli_octal_values_rule.rs +60 -0
  95. package/tests/cli_quoted_strings_rule.rs +47 -0
  96. package/tests/cli_toml_config.rs +119 -0
  97. package/tests/cli_trailing_spaces_rule.rs +77 -0
  98. package/tests/cli_truthy_rule.rs +83 -0
  99. package/tests/cli_yaml_files_negation.rs +45 -0
  100. package/tests/colons_rule.rs +303 -0
  101. package/tests/common/compat.rs +114 -0
  102. package/tests/common/fake_env.rs +93 -0
  103. package/tests/common/mod.rs +1 -0
  104. package/tests/conf_builtin.rs +9 -0
  105. package/tests/config_anchors.rs +84 -0
  106. package/tests/config_braces.rs +121 -0
  107. package/tests/config_brackets.rs +127 -0
  108. package/tests/config_commas.rs +79 -0
  109. package/tests/config_comments.rs +65 -0
  110. package/tests/config_comments_indentation.rs +20 -0
  111. package/tests/config_deep_merge_nonstring_key.rs +24 -0
  112. package/tests/config_document_end.rs +54 -0
  113. package/tests/config_document_start.rs +55 -0
  114. package/tests/config_empty_lines.rs +48 -0
  115. package/tests/config_empty_values.rs +35 -0
  116. package/tests/config_env_errors.rs +23 -0
  117. package/tests/config_env_invalid_inline.rs +15 -0
  118. package/tests/config_env_missing.rs +63 -0
  119. package/tests/config_env_shim.rs +301 -0
  120. package/tests/config_explicit_file_parse_error.rs +55 -0
  121. package/tests/config_extended_features.rs +225 -0
  122. package/tests/config_extends_inline.rs +185 -0
  123. package/tests/config_extends_sequence.rs +18 -0
  124. package/tests/config_find_project_home_boundary.rs +54 -0
  125. package/tests/config_find_project_two_files_in_cwd.rs +47 -0
  126. package/tests/config_float_values.rs +34 -0
  127. package/tests/config_from_yaml_paths.rs +32 -0
  128. package/tests/config_hyphens.rs +51 -0
  129. package/tests/config_ignore_errors.rs +243 -0
  130. package/tests/config_ignore_overrides.rs +83 -0
  131. package/tests/config_indentation.rs +65 -0
  132. package/tests/config_invalid_globs.rs +16 -0
  133. package/tests/config_invalid_types.rs +19 -0
  134. package/tests/config_key_duplicates.rs +34 -0
  135. package/tests/config_key_ordering.rs +70 -0
  136. package/tests/config_line_length.rs +65 -0
  137. package/tests/config_locale.rs +111 -0
  138. package/tests/config_merge.rs +26 -0
  139. package/tests/config_new_lines.rs +89 -0
  140. package/tests/config_octal_values.rs +33 -0
  141. package/tests/config_quoted_strings.rs +195 -0
  142. package/tests/config_rule_level.rs +147 -0
  143. package/tests/config_rules_non_string_keys.rs +23 -0
  144. package/tests/config_scalar_overrides.rs +27 -0
  145. package/tests/config_to_toml.rs +110 -0
  146. package/tests/config_toml_coverage.rs +80 -0
  147. package/tests/config_toml_discovery.rs +304 -0
  148. package/tests/config_trailing_spaces.rs +152 -0
  149. package/tests/config_truthy.rs +77 -0
  150. package/tests/config_yaml_files.rs +62 -0
  151. package/tests/config_yaml_files_all_non_string.rs +15 -0
  152. package/tests/config_yaml_files_empty.rs +30 -0
  153. package/tests/coverage_commas.rs +46 -0
  154. package/tests/decoder_decode.rs +338 -0
  155. package/tests/discover_config_bin_all.rs +66 -0
  156. package/tests/discover_config_bin_env_invalid_yaml.rs +26 -0
  157. package/tests/discover_config_bin_project_config_parse_error.rs +24 -0
  158. package/tests/discover_config_bin_user_global_error.rs +26 -0
  159. package/tests/discover_module.rs +30 -0
  160. package/tests/discover_per_file_dir.rs +10 -0
  161. package/tests/discover_per_file_project_config_error.rs +21 -0
  162. package/tests/float_values.rs +43 -0
  163. package/tests/lint_multi_errors.rs +32 -0
  164. package/tests/main_yaml_ok_filtering.rs +30 -0
  165. package/tests/migrate_module.rs +259 -0
  166. package/tests/resolve_ctx_empty_parent.rs +16 -0
  167. package/tests/rule_anchors.rs +442 -0
  168. package/tests/rule_braces.rs +258 -0
  169. package/tests/rule_brackets.rs +217 -0
  170. package/tests/rule_commas.rs +205 -0
  171. package/tests/rule_comments.rs +197 -0
  172. package/tests/rule_comments_indentation.rs +127 -0
  173. package/tests/rule_document_end.rs +118 -0
  174. package/tests/rule_document_start.rs +60 -0
  175. package/tests/rule_empty_lines.rs +96 -0
  176. package/tests/rule_empty_values.rs +102 -0
  177. package/tests/rule_float_values.rs +109 -0
  178. package/tests/rule_hyphens.rs +65 -0
  179. package/tests/rule_indentation.rs +455 -0
  180. package/tests/rule_key_duplicates.rs +76 -0
  181. package/tests/rule_key_ordering.rs +207 -0
  182. package/tests/rule_line_length.rs +200 -0
  183. package/tests/rule_new_lines.rs +51 -0
  184. package/tests/rule_octal_values.rs +53 -0
  185. package/tests/rule_quoted_strings.rs +290 -0
  186. package/tests/rule_trailing_spaces.rs +41 -0
  187. package/tests/rule_truthy.rs +236 -0
  188. package/tests/user_global_invalid_yaml.rs +32 -0
  189. package/tests/yamllint_compat_anchors.rs +280 -0
  190. package/tests/yamllint_compat_braces.rs +411 -0
  191. package/tests/yamllint_compat_brackets.rs +364 -0
  192. package/tests/yamllint_compat_colons.rs +298 -0
  193. package/tests/yamllint_compat_colors.rs +80 -0
  194. package/tests/yamllint_compat_commas.rs +375 -0
  195. package/tests/yamllint_compat_comments.rs +167 -0
  196. package/tests/yamllint_compat_comments_indentation.rs +281 -0
  197. package/tests/yamllint_compat_config.rs +170 -0
  198. package/tests/yamllint_compat_document_end.rs +243 -0
  199. package/tests/yamllint_compat_document_start.rs +136 -0
  200. package/tests/yamllint_compat_empty_lines.rs +117 -0
  201. package/tests/yamllint_compat_empty_values.rs +179 -0
  202. package/tests/yamllint_compat_float_values.rs +216 -0
  203. package/tests/yamllint_compat_hyphens.rs +223 -0
  204. package/tests/yamllint_compat_indentation.rs +398 -0
  205. package/tests/yamllint_compat_key_duplicates.rs +139 -0
  206. package/tests/yamllint_compat_key_ordering.rs +170 -0
  207. package/tests/yamllint_compat_line_length.rs +375 -0
  208. package/tests/yamllint_compat_list.rs +127 -0
  209. package/tests/yamllint_compat_new_line.rs +133 -0
  210. package/tests/yamllint_compat_newline_types.rs +185 -0
  211. package/tests/yamllint_compat_octal_values.rs +172 -0
  212. package/tests/yamllint_compat_quoted_strings.rs +154 -0
  213. package/tests/yamllint_compat_syntax.rs +200 -0
  214. package/tests/yamllint_compat_trailing_spaces.rs +162 -0
  215. package/tests/yamllint_compat_truthy.rs +130 -0
  216. package/tests/yamllint_compat_yaml_files.rs +81 -0
  217. package/typos.toml +2 -0
@@ -0,0 +1,104 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn braces_reports_errors() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("bad.yaml");
18
+ fs::write(&file, "---\nobject: { key: 1 }\n").unwrap();
19
+
20
+ let exe = env!("CARGO_BIN_EXE_ryl");
21
+ let (code, stdout, stderr) = run(Command::new(exe).arg(&file));
22
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
23
+ let output = if stderr.is_empty() { stdout } else { stderr };
24
+ assert!(
25
+ output.contains("too many spaces inside braces"),
26
+ "missing message: {output}"
27
+ );
28
+ assert!(
29
+ output.contains("braces"),
30
+ "rule id missing from output: {output}"
31
+ );
32
+ }
33
+
34
+ #[test]
35
+ fn forbid_flow_mappings_reports_error() {
36
+ let dir = tempdir().unwrap();
37
+ let file = dir.path().join("flow.yaml");
38
+ fs::write(&file, "---\nobject: {key: 1}\n").unwrap();
39
+ let config = dir.path().join("config.yaml");
40
+ fs::write(
41
+ &config,
42
+ "rules:\n document-start: disable\n braces:\n forbid: true\n",
43
+ )
44
+ .unwrap();
45
+
46
+ let exe = env!("CARGO_BIN_EXE_ryl");
47
+ let (code, stdout, stderr) =
48
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
49
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
50
+ let output = if stderr.is_empty() { stdout } else { stderr };
51
+ assert!(
52
+ output.contains("forbidden flow mapping"),
53
+ "missing message: {output}"
54
+ );
55
+ }
56
+
57
+ #[test]
58
+ fn empty_spacing_config_is_respected() {
59
+ let dir = tempdir().unwrap();
60
+ let file = dir.path().join("empty.yaml");
61
+ fs::write(&file, "---\nobject: {}\n").unwrap();
62
+ let config = dir.path().join("config.yaml");
63
+ fs::write(
64
+ &config,
65
+ "rules:\n document-start: disable\n braces:\n min-spaces-inside-empty: 1\n",
66
+ )
67
+ .unwrap();
68
+
69
+ let exe = env!("CARGO_BIN_EXE_ryl");
70
+ let (code, stdout, stderr) =
71
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
72
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
73
+ let output = if stderr.is_empty() { stdout } else { stderr };
74
+ assert!(
75
+ output.contains("too few spaces inside empty braces"),
76
+ "missing message: {output}"
77
+ );
78
+ }
79
+
80
+ #[test]
81
+ fn warning_level_does_not_fail() {
82
+ let dir = tempdir().unwrap();
83
+ let file = dir.path().join("warn.yaml");
84
+ fs::write(&file, "---\nobject: { key: 1 }\n").unwrap();
85
+ let config = dir.path().join("config.yaml");
86
+ fs::write(
87
+ &config,
88
+ "rules:\n document-start: disable\n braces:\n level: warning\n",
89
+ )
90
+ .unwrap();
91
+
92
+ let exe = env!("CARGO_BIN_EXE_ryl");
93
+ let (code, stdout, stderr) =
94
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
95
+ assert_eq!(
96
+ code, 0,
97
+ "warnings should not fail: stdout={stdout} stderr={stderr}"
98
+ );
99
+ let output = if stderr.is_empty() { stdout } else { stderr };
100
+ assert!(
101
+ output.contains("warning"),
102
+ "expected warning output: {output}"
103
+ );
104
+ }
@@ -0,0 +1,104 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn brackets_reports_errors() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("bad.yaml");
18
+ fs::write(&file, "---\nobject: [ 1, 2 ]\n").unwrap();
19
+
20
+ let exe = env!("CARGO_BIN_EXE_ryl");
21
+ let (code, stdout, stderr) = run(Command::new(exe).arg(&file));
22
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
23
+ let output = if stderr.is_empty() { stdout } else { stderr };
24
+ assert!(
25
+ output.contains("too many spaces inside brackets"),
26
+ "missing message: {output}"
27
+ );
28
+ assert!(
29
+ output.contains("brackets"),
30
+ "rule id missing from output: {output}"
31
+ );
32
+ }
33
+
34
+ #[test]
35
+ fn forbid_flow_sequences_reports_error() {
36
+ let dir = tempdir().unwrap();
37
+ let file = dir.path().join("flow.yaml");
38
+ fs::write(&file, "---\nobject: [1, 2]\n").unwrap();
39
+ let config = dir.path().join("config.yaml");
40
+ fs::write(
41
+ &config,
42
+ "rules:\n document-start: disable\n brackets:\n forbid: true\n",
43
+ )
44
+ .unwrap();
45
+
46
+ let exe = env!("CARGO_BIN_EXE_ryl");
47
+ let (code, stdout, stderr) =
48
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
49
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
50
+ let output = if stderr.is_empty() { stdout } else { stderr };
51
+ assert!(
52
+ output.contains("forbidden flow sequence"),
53
+ "missing message: {output}"
54
+ );
55
+ }
56
+
57
+ #[test]
58
+ fn empty_spacing_config_is_respected() {
59
+ let dir = tempdir().unwrap();
60
+ let file = dir.path().join("empty.yaml");
61
+ fs::write(&file, "---\nobject: []\n").unwrap();
62
+ let config = dir.path().join("config.yaml");
63
+ fs::write(
64
+ &config,
65
+ "rules:\n document-start: disable\n brackets:\n min-spaces-inside-empty: 1\n",
66
+ )
67
+ .unwrap();
68
+
69
+ let exe = env!("CARGO_BIN_EXE_ryl");
70
+ let (code, stdout, stderr) =
71
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
72
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
73
+ let output = if stderr.is_empty() { stdout } else { stderr };
74
+ assert!(
75
+ output.contains("too few spaces inside empty brackets"),
76
+ "missing message: {output}"
77
+ );
78
+ }
79
+
80
+ #[test]
81
+ fn warning_level_does_not_fail() {
82
+ let dir = tempdir().unwrap();
83
+ let file = dir.path().join("warn.yaml");
84
+ fs::write(&file, "---\nobject: [ 1, 2 ]\n").unwrap();
85
+ let config = dir.path().join("config.yaml");
86
+ fs::write(
87
+ &config,
88
+ "rules:\n document-start: disable\n brackets:\n level: warning\n",
89
+ )
90
+ .unwrap();
91
+
92
+ let exe = env!("CARGO_BIN_EXE_ryl");
93
+ let (code, stdout, stderr) =
94
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
95
+ assert_eq!(
96
+ code, 0,
97
+ "warnings should not fail: stdout={stdout} stderr={stderr}"
98
+ );
99
+ let output = if stderr.is_empty() { stdout } else { stderr };
100
+ assert!(
101
+ output.contains("warning"),
102
+ "expected warning output: {output}"
103
+ );
104
+ }
@@ -0,0 +1,65 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn colons_reports_spacing_errors() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("bad.yaml");
18
+ fs::write(&file, "---\nkey : value\n").unwrap();
19
+
20
+ let config = dir.path().join("config.yaml");
21
+ fs::write(
22
+ &config,
23
+ "rules:\n document-start: disable\n colons: enable\n",
24
+ )
25
+ .unwrap();
26
+
27
+ let exe = env!("CARGO_BIN_EXE_ryl");
28
+ let (code, stdout, stderr) =
29
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
30
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
31
+ let output = if stderr.is_empty() { stdout } else { stderr };
32
+ assert!(
33
+ output.contains("too many spaces before colon"),
34
+ "missing before-colon message: {output}"
35
+ );
36
+ assert!(
37
+ output.contains("too many spaces after colon"),
38
+ "missing after-colon message: {output}"
39
+ );
40
+ assert!(output.contains("colons"), "rule id missing: {output}");
41
+ }
42
+
43
+ #[test]
44
+ fn colons_reports_explicit_key_spacing() {
45
+ let dir = tempdir().unwrap();
46
+ let file = dir.path().join("explicit.yaml");
47
+ fs::write(&file, "---\n? key\n: value\n").unwrap();
48
+
49
+ let config = dir.path().join("config.yaml");
50
+ fs::write(
51
+ &config,
52
+ "rules:\n document-start: disable\n colons: enable\n",
53
+ )
54
+ .unwrap();
55
+
56
+ let exe = env!("CARGO_BIN_EXE_ryl");
57
+ let (code, stdout, stderr) =
58
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
59
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
60
+ let output = if stderr.is_empty() { stdout } else { stderr };
61
+ assert!(
62
+ output.contains("too many spaces after question mark"),
63
+ "missing question mark message: {output}"
64
+ );
65
+ }
@@ -0,0 +1,104 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn commas_reports_errors() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("bad.yaml");
18
+ fs::write(&file, "---\n[1,2]\n").unwrap();
19
+
20
+ let exe = env!("CARGO_BIN_EXE_ryl");
21
+ let (code, stdout, stderr) = run(Command::new(exe).arg(&file));
22
+ assert_eq!(code, 1, "expected failure: stdout={stdout} stderr={stderr}");
23
+ let output = if stderr.is_empty() { stdout } else { stderr };
24
+ assert!(
25
+ output.contains("too few spaces after comma"),
26
+ "missing message: {output}"
27
+ );
28
+ assert!(
29
+ output.contains("commas"),
30
+ "rule id missing from output: {output}"
31
+ );
32
+ }
33
+
34
+ #[test]
35
+ fn warning_level_does_not_fail() {
36
+ let dir = tempdir().unwrap();
37
+ let file = dir.path().join("warn.yaml");
38
+ fs::write(&file, "---\n[1,2]\n").unwrap();
39
+ let config = dir.path().join("config.yml");
40
+ fs::write(
41
+ &config,
42
+ "rules:\n document-start: disable\n commas:\n level: warning\n",
43
+ )
44
+ .unwrap();
45
+
46
+ let exe = env!("CARGO_BIN_EXE_ryl");
47
+ let (code, stdout, stderr) =
48
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
49
+ assert_eq!(
50
+ code, 0,
51
+ "warnings should not fail: stdout={stdout} stderr={stderr}"
52
+ );
53
+ let output = if stderr.is_empty() { stdout } else { stderr };
54
+ assert!(
55
+ output.contains("warning"),
56
+ "expected warning output: {output}"
57
+ );
58
+ }
59
+
60
+ #[test]
61
+ fn rule_ignore_skips_file() {
62
+ let dir = tempdir().unwrap();
63
+ let file = dir.path().join("ignored.yaml");
64
+ fs::write(&file, "---\n[1,2]\n").unwrap();
65
+ let config = dir.path().join("config.yml");
66
+ fs::write(
67
+ &config,
68
+ "rules:\n document-start: disable\n commas:\n ignore:\n - ignored.yaml\n",
69
+ )
70
+ .unwrap();
71
+
72
+ let exe = env!("CARGO_BIN_EXE_ryl");
73
+ let (code, stdout, stderr) =
74
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
75
+ assert_eq!(
76
+ code, 0,
77
+ "ignored file should pass: stdout={stdout} stderr={stderr}"
78
+ );
79
+ assert!(stdout.trim().is_empty(), "expected no stdout: {stdout}");
80
+ assert!(stderr.trim().is_empty(), "expected no stderr: {stderr}");
81
+ }
82
+
83
+ #[test]
84
+ fn relaxed_spacing_allows_compact_flow() {
85
+ let dir = tempdir().unwrap();
86
+ let file = dir.path().join("compact.yaml");
87
+ fs::write(&file, "---\n[1,2]\n").unwrap();
88
+ let config = dir.path().join("config.yml");
89
+ fs::write(
90
+ &config,
91
+ "rules:\n document-start: disable\n commas:\n max-spaces-before: -1\n min-spaces-after: 0\n max-spaces-after: -1\n",
92
+ )
93
+ .unwrap();
94
+
95
+ let exe = env!("CARGO_BIN_EXE_ryl");
96
+ let (code, stdout, stderr) =
97
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
98
+ assert_eq!(
99
+ code, 0,
100
+ "relaxed spacing should pass: stdout={stdout} stderr={stderr}"
101
+ );
102
+ assert!(stdout.trim().is_empty(), "expected no stdout: {stdout}");
103
+ assert!(stderr.trim().is_empty(), "expected no stderr: {stderr}");
104
+ }
@@ -0,0 +1,61 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn comments_indentation_reports_error() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("bad.yaml");
18
+ fs::write(&file, "obj:\n # wrong\n value: 1\n").unwrap();
19
+ let config = dir.path().join("config.yaml");
20
+ fs::write(
21
+ &config,
22
+ "rules:\n document-start: disable\n comments-indentation: enable\n",
23
+ )
24
+ .unwrap();
25
+
26
+ let exe = env!("CARGO_BIN_EXE_ryl");
27
+ let (code, stdout, stderr) =
28
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
29
+
30
+ assert_eq!(code, 1, "expected exit 1: stdout={stdout} stderr={stderr}");
31
+ let output = if stderr.is_empty() { &stdout } else { &stderr };
32
+ assert!(
33
+ output.contains("comments-indentation"),
34
+ "missing rule id: {output}"
35
+ );
36
+ assert!(
37
+ output.contains("comment not indented like content"),
38
+ "missing message: {output}"
39
+ );
40
+ }
41
+
42
+ #[test]
43
+ fn comments_indentation_allows_aligned_comment() {
44
+ let dir = tempdir().unwrap();
45
+ let file = dir.path().join("ok.yaml");
46
+ fs::write(&file, "obj:\n # ok\n value: 1\n").unwrap();
47
+ let config = dir.path().join("config.yaml");
48
+ fs::write(
49
+ &config,
50
+ "rules:\n document-start: disable\n comments-indentation: enable\n",
51
+ )
52
+ .unwrap();
53
+
54
+ let exe = env!("CARGO_BIN_EXE_ryl");
55
+ let (code, stdout, stderr) =
56
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
57
+
58
+ assert_eq!(code, 0, "expected success: stdout={stdout} stderr={stderr}");
59
+ assert!(stdout.is_empty(), "expected no stdout: {stdout}");
60
+ assert!(stderr.is_empty(), "expected no stderr: {stderr}");
61
+ }
@@ -0,0 +1,67 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn comments_rule_emits_diagnostics() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("bad.yaml");
18
+ fs::write(&file, "#comment\nkey: value # comment\nvalue: foo #bar\n").unwrap();
19
+
20
+ let config = dir.path().join("config.yaml");
21
+ fs::write(
22
+ &config,
23
+ "rules:\n document-start: disable\n comments:\n require-starting-space: true\n ignore-shebangs: true\n min-spaces-from-content: 2\n",
24
+ )
25
+ .unwrap();
26
+
27
+ let exe = env!("CARGO_BIN_EXE_ryl");
28
+ let (code, stdout, stderr) =
29
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
30
+
31
+ assert_eq!(code, 1, "expected exit 1: stdout={stdout} stderr={stderr}");
32
+ let output = if stderr.is_empty() { &stdout } else { &stderr };
33
+ assert!(
34
+ output.contains("comments"),
35
+ "missing rule identifier in output: {output}"
36
+ );
37
+ assert!(
38
+ output.contains("missing starting space in comment"),
39
+ "missing starting-space message: {output}"
40
+ );
41
+ assert!(
42
+ output.contains("too few spaces before comment: expected 2"),
43
+ "missing spacing message: {output}"
44
+ );
45
+ }
46
+
47
+ #[test]
48
+ fn comments_rule_ignores_shebang_when_enabled() {
49
+ let dir = tempdir().unwrap();
50
+ let file = dir.path().join("shebang.yaml");
51
+ fs::write(&file, "#!/usr/bin/env foo\n").unwrap();
52
+
53
+ let config = dir.path().join("config.yaml");
54
+ fs::write(
55
+ &config,
56
+ "rules:\n document-start: disable\n comments:\n require-starting-space: true\n ignore-shebangs: true\n",
57
+ )
58
+ .unwrap();
59
+
60
+ let exe = env!("CARGO_BIN_EXE_ryl");
61
+ let (code, stdout, stderr) =
62
+ run(Command::new(exe).arg("-c").arg(&config).arg(&file));
63
+
64
+ assert_eq!(code, 0, "expected success: stdout={stdout} stderr={stderr}");
65
+ assert!(stdout.is_empty(), "expected no stdout: {stdout}");
66
+ assert!(stderr.is_empty(), "expected no stderr: {stderr}");
67
+ }
@@ -0,0 +1,30 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("process");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn invalid_inline_config_causes_exit_2() {
16
+ let dir = tempdir().unwrap();
17
+ let file = dir.path().join("file.yaml");
18
+ fs::write(&file, "key: value\n").unwrap();
19
+
20
+ let exe = env!("CARGO_BIN_EXE_ryl");
21
+ let (code, _out, err) = run(Command::new(exe)
22
+ .arg("-d")
23
+ .arg("extends: missing-config")
24
+ .arg(&file));
25
+ assert_eq!(code, 2, "missing inline extends should exit 2: {err}");
26
+ assert!(
27
+ err.contains("failed to read"),
28
+ "expected config read error: {err}"
29
+ );
30
+ }
@@ -0,0 +1,66 @@
1
+ use std::fs;
2
+ use std::process::Command;
3
+
4
+ use tempfile::tempdir;
5
+
6
+ fn run(cmd: &mut Command) -> (i32, String, String) {
7
+ let out = cmd.output().expect("failed to run ryl");
8
+ let code = out.status.code().unwrap_or(-1);
9
+ let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
10
+ let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
11
+ (code, stdout, stderr)
12
+ }
13
+
14
+ #[test]
15
+ fn config_file_ignores_docs_globally() {
16
+ let td = tempdir().unwrap();
17
+ let root = td.path();
18
+ fs::create_dir_all(root.join("docs")).unwrap();
19
+ fs::write(root.join("a.yaml"), "a: 1\n").unwrap();
20
+ fs::write(root.join("docs/ignored.yaml"), "x: 0\n").unwrap();
21
+
22
+ let cfg = root.join("cfg.yml");
23
+ fs::write(&cfg, "ignore: ['docs/**']\n").unwrap();
24
+
25
+ let exe = env!("CARGO_BIN_EXE_ryl");
26
+ let (code, out, err) = run(Command::new(exe)
27
+ .arg("--list-files")
28
+ .arg("-c")
29
+ .arg(&cfg)
30
+ .arg(root));
31
+ assert_eq!(code, 0, "expected success: {err}");
32
+ assert!(out.contains("a.yaml"));
33
+ assert!(!out.contains("docs/ignored.yaml"));
34
+ }
35
+
36
+ #[test]
37
+ fn config_data_yaml_files_only_lists_dot_yamllint_yml() {
38
+ let td = tempdir().unwrap();
39
+ let root = td.path();
40
+ fs::write(root.join("a.yaml"), "a: 1\n").unwrap();
41
+ fs::write(root.join(".yamllint.yml"), "rules: {}\n").unwrap();
42
+
43
+ let exe = env!("CARGO_BIN_EXE_ryl");
44
+ let (code, out, err) = run(Command::new(exe)
45
+ .arg("--list-files")
46
+ .arg("-d")
47
+ .arg("yaml-files: ['**/.yamllint.yml']\n")
48
+ .arg(root));
49
+ assert_eq!(code, 0, "expected success: {err}");
50
+ assert!(out.contains(".yamllint.yml"));
51
+ assert!(!out.contains("a.yaml"));
52
+ }
53
+
54
+ #[test]
55
+ fn format_strict_no_warnings_are_accepted() {
56
+ let td = tempdir().unwrap();
57
+ let exe = env!("CARGO_BIN_EXE_ryl");
58
+ let (code, _out, err) = run(Command::new(exe)
59
+ .arg("--list-files")
60
+ .arg("-f")
61
+ .arg("standard")
62
+ .arg("-s")
63
+ .arg("--no-warnings")
64
+ .arg(td.path()));
65
+ assert_eq!(code, 0, "expected success: {err}");
66
+ }