thailint 0.3.2__tar.gz → 0.4.0__tar.gz

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 (83) hide show
  1. {thailint-0.3.2 → thailint-0.4.0}/PKG-INFO +2 -2
  2. {thailint-0.3.2 → thailint-0.4.0}/README.md +1 -1
  3. {thailint-0.3.2 → thailint-0.4.0}/pyproject.toml +1 -1
  4. {thailint-0.3.2 → thailint-0.4.0}/src/cli.py +135 -0
  5. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/config.py +9 -4
  6. thailint-0.4.0/src/templates/thailint_config_template.yaml +132 -0
  7. {thailint-0.3.2 → thailint-0.4.0}/CHANGELOG.md +0 -0
  8. {thailint-0.3.2 → thailint-0.4.0}/LICENSE +0 -0
  9. {thailint-0.3.2 → thailint-0.4.0}/src/__init__.py +0 -0
  10. {thailint-0.3.2 → thailint-0.4.0}/src/analyzers/__init__.py +0 -0
  11. {thailint-0.3.2 → thailint-0.4.0}/src/analyzers/typescript_base.py +0 -0
  12. {thailint-0.3.2 → thailint-0.4.0}/src/api.py +0 -0
  13. {thailint-0.3.2 → thailint-0.4.0}/src/config.py +0 -0
  14. {thailint-0.3.2 → thailint-0.4.0}/src/core/__init__.py +0 -0
  15. {thailint-0.3.2 → thailint-0.4.0}/src/core/base.py +0 -0
  16. {thailint-0.3.2 → thailint-0.4.0}/src/core/cli_utils.py +0 -0
  17. {thailint-0.3.2 → thailint-0.4.0}/src/core/config_parser.py +0 -0
  18. {thailint-0.3.2 → thailint-0.4.0}/src/core/linter_utils.py +0 -0
  19. {thailint-0.3.2 → thailint-0.4.0}/src/core/registry.py +0 -0
  20. {thailint-0.3.2 → thailint-0.4.0}/src/core/rule_discovery.py +0 -0
  21. {thailint-0.3.2 → thailint-0.4.0}/src/core/types.py +0 -0
  22. {thailint-0.3.2 → thailint-0.4.0}/src/core/violation_builder.py +0 -0
  23. {thailint-0.3.2 → thailint-0.4.0}/src/linter_config/__init__.py +0 -0
  24. {thailint-0.3.2 → thailint-0.4.0}/src/linter_config/ignore.py +0 -0
  25. {thailint-0.3.2 → thailint-0.4.0}/src/linter_config/loader.py +0 -0
  26. {thailint-0.3.2 → thailint-0.4.0}/src/linters/__init__.py +0 -0
  27. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/__init__.py +0 -0
  28. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/base_token_analyzer.py +0 -0
  29. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/block_filter.py +0 -0
  30. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/block_grouper.py +0 -0
  31. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/cache.py +0 -0
  32. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/cache_query.py +0 -0
  33. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/config.py +0 -0
  34. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/config_loader.py +0 -0
  35. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/deduplicator.py +0 -0
  36. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/duplicate_storage.py +0 -0
  37. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/file_analyzer.py +0 -0
  38. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/inline_ignore.py +0 -0
  39. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/linter.py +0 -0
  40. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/python_analyzer.py +0 -0
  41. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/storage_initializer.py +0 -0
  42. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/token_hasher.py +0 -0
  43. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/typescript_analyzer.py +0 -0
  44. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/violation_builder.py +0 -0
  45. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/violation_filter.py +0 -0
  46. {thailint-0.3.2 → thailint-0.4.0}/src/linters/dry/violation_generator.py +0 -0
  47. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/__init__.py +0 -0
  48. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/config_loader.py +0 -0
  49. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/directory_matcher.py +0 -0
  50. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/linter.py +0 -0
  51. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/path_resolver.py +0 -0
  52. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/pattern_matcher.py +0 -0
  53. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/pattern_validator.py +0 -0
  54. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/rule_checker.py +0 -0
  55. {thailint-0.3.2 → thailint-0.4.0}/src/linters/file_placement/violation_factory.py +0 -0
  56. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/__init__.py +0 -0
  57. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/context_analyzer.py +0 -0
  58. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/linter.py +0 -0
  59. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/python_analyzer.py +0 -0
  60. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/typescript_analyzer.py +0 -0
  61. {thailint-0.3.2 → thailint-0.4.0}/src/linters/magic_numbers/violation_builder.py +0 -0
  62. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/__init__.py +0 -0
  63. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/config.py +0 -0
  64. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/linter.py +0 -0
  65. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/python_analyzer.py +0 -0
  66. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/typescript_analyzer.py +0 -0
  67. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/typescript_function_extractor.py +0 -0
  68. {thailint-0.3.2 → thailint-0.4.0}/src/linters/nesting/violation_builder.py +0 -0
  69. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/__init__.py +0 -0
  70. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/class_analyzer.py +0 -0
  71. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/config.py +0 -0
  72. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/heuristics.py +0 -0
  73. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/linter.py +0 -0
  74. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/metrics_evaluator.py +0 -0
  75. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/python_analyzer.py +0 -0
  76. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/typescript_analyzer.py +0 -0
  77. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/typescript_metrics_calculator.py +0 -0
  78. {thailint-0.3.2 → thailint-0.4.0}/src/linters/srp/violation_builder.py +0 -0
  79. {thailint-0.3.2 → thailint-0.4.0}/src/orchestrator/__init__.py +0 -0
  80. {thailint-0.3.2 → thailint-0.4.0}/src/orchestrator/core.py +0 -0
  81. {thailint-0.3.2 → thailint-0.4.0}/src/orchestrator/language_detector.py +0 -0
  82. {thailint-0.3.2 → thailint-0.4.0}/src/utils/__init__.py +0 -0
  83. {thailint-0.3.2 → thailint-0.4.0}/src/utils/project_root.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: thailint
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages
5
5
  License: MIT
6
6
  Keywords: linter,ai,code-quality,static-analysis,file-placement,governance,multi-language,cli,docker,python
@@ -36,7 +36,7 @@ Description-Content-Type: text/markdown
36
36
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
37
37
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
38
38
  [![Tests](https://img.shields.io/badge/tests-253%2F253%20passing-brightgreen.svg)](tests/)
39
- [![Coverage](https://img.shields.io/badge/coverage-88%25-brightgreen.svg)](htmlcov/)
39
+ [![Coverage](https://img.shields.io/badge/coverage-87%25-brightgreen.svg)](htmlcov/)
40
40
 
41
41
  The AI Linter - Enterprise-ready linting and governance for AI-generated code across multiple languages.
42
42
 
@@ -3,7 +3,7 @@
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
5
5
  [![Tests](https://img.shields.io/badge/tests-253%2F253%20passing-brightgreen.svg)](tests/)
6
- [![Coverage](https://img.shields.io/badge/coverage-88%25-brightgreen.svg)](htmlcov/)
6
+ [![Coverage](https://img.shields.io/badge/coverage-87%25-brightgreen.svg)](htmlcov/)
7
7
 
8
8
  The AI Linter - Enterprise-ready linting and governance for AI-generated code across multiple languages.
9
9
 
@@ -17,7 +17,7 @@ build-backend = "poetry.core.masonry.api"
17
17
 
18
18
  [tool.poetry]
19
19
  name = "thailint"
20
- version = "0.3.2"
20
+ version = "0.4.0"
21
21
  description = "The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages"
22
22
  authors = ["Steve Jackson"]
23
23
  license = "MIT"
@@ -362,6 +362,141 @@ def config_reset(ctx, yes: bool):
362
362
  sys.exit(1)
363
363
 
364
364
 
365
+ @cli.command("init-config")
366
+ @click.option(
367
+ "--preset",
368
+ "-p",
369
+ type=click.Choice(["strict", "standard", "lenient"]),
370
+ default="standard",
371
+ help="Configuration preset",
372
+ )
373
+ @click.option("--non-interactive", is_flag=True, help="Skip interactive prompts (for AI agents)")
374
+ @click.option("--force", is_flag=True, help="Overwrite existing .thailint.yaml file")
375
+ @click.option(
376
+ "--output", "-o", type=click.Path(), default=".thailint.yaml", help="Output file path"
377
+ )
378
+ def init_config(preset: str, non_interactive: bool, force: bool, output: str):
379
+ """
380
+ Generate a .thailint.yaml configuration file with preset values.
381
+
382
+ Creates a richly-commented configuration file with sensible defaults
383
+ and optional customizations for different strictness levels.
384
+
385
+ For AI agents, use --non-interactive mode:
386
+ thailint init-config --non-interactive --preset lenient
387
+
388
+ Presets:
389
+ strict: Minimal allowed numbers (only -1, 0, 1)
390
+ standard: Balanced defaults (includes 2, 3, 4, 5, 10, 100, 1000)
391
+ lenient: Includes time conversions (adds 60, 3600)
392
+
393
+ Examples:
394
+
395
+ \\b
396
+ # Interactive mode (default, for humans)
397
+ thailint init-config
398
+
399
+ \\b
400
+ # Non-interactive mode (for AI agents)
401
+ thailint init-config --non-interactive
402
+
403
+ \\b
404
+ # Generate with lenient preset
405
+ thailint init-config --preset lenient
406
+
407
+ \\b
408
+ # Overwrite existing config
409
+ thailint init-config --force
410
+
411
+ \\b
412
+ # Custom output path
413
+ thailint init-config --output my-config.yaml
414
+ """
415
+ output_path = Path(output)
416
+
417
+ # Check if file exists (unless --force)
418
+ if output_path.exists() and not force:
419
+ click.echo(f"Error: {output} already exists", err=True)
420
+ click.echo("", err=True)
421
+ click.echo("Use --force to overwrite:", err=True)
422
+ click.echo(" thailint init-config --force", err=True)
423
+ sys.exit(1)
424
+
425
+ # Interactive mode: Ask user for preferences
426
+ if not non_interactive:
427
+ click.echo("thai-lint Configuration Generator")
428
+ click.echo("=" * 50)
429
+ click.echo("")
430
+ click.echo("This will create a .thailint.yaml configuration file.")
431
+ click.echo("For non-interactive mode (AI agents), use:")
432
+ click.echo(" thailint init-config --non-interactive")
433
+ click.echo("")
434
+
435
+ # Ask for preset
436
+ click.echo("Available presets:")
437
+ click.echo(" strict: Only -1, 0, 1 allowed (strictest)")
438
+ click.echo(" standard: -1, 0, 1, 2, 3, 4, 5, 10, 100, 1000 (balanced)")
439
+ click.echo(" lenient: Includes time conversions 60, 3600 (most permissive)")
440
+ click.echo("")
441
+
442
+ preset = click.prompt(
443
+ "Choose preset", type=click.Choice(["strict", "standard", "lenient"]), default=preset
444
+ )
445
+
446
+ # Generate config based on preset
447
+ config_content = _generate_config_content(preset)
448
+
449
+ # Write config file
450
+ try:
451
+ output_path.write_text(config_content, encoding="utf-8")
452
+ click.echo("")
453
+ click.echo(f"✓ Created {output}")
454
+ click.echo(f"✓ Preset: {preset}")
455
+ click.echo("")
456
+ click.echo("Next steps:")
457
+ click.echo(f" 1. Review and customize {output}")
458
+ click.echo(" 2. Run: thailint magic-numbers .")
459
+ click.echo(" 3. See docs: https://github.com/your-org/thai-lint")
460
+ except OSError as e:
461
+ click.echo(f"Error writing config file: {e}", err=True)
462
+ sys.exit(1)
463
+
464
+
465
+ def _generate_config_content(preset: str) -> str:
466
+ """Generate config file content based on preset."""
467
+ # Preset configurations
468
+ presets = {
469
+ "strict": {
470
+ "allowed_numbers": "[-1, 0, 1]",
471
+ "max_small_integer": "3",
472
+ "description": "Strict (only universal values)",
473
+ },
474
+ "standard": {
475
+ "allowed_numbers": "[-1, 0, 1, 2, 3, 4, 5, 10, 100, 1000]",
476
+ "max_small_integer": "10",
477
+ "description": "Standard (balanced defaults)",
478
+ },
479
+ "lenient": {
480
+ "allowed_numbers": "[-1, 0, 1, 2, 3, 4, 5, 10, 60, 100, 1000, 3600]",
481
+ "max_small_integer": "10",
482
+ "description": "Lenient (includes time conversions)",
483
+ },
484
+ }
485
+
486
+ config = presets[preset]
487
+
488
+ # Read template
489
+ template_path = Path(__file__).parent / "templates" / "thailint_config_template.yaml"
490
+ template = template_path.read_text(encoding="utf-8")
491
+
492
+ # Replace placeholders
493
+ content = template.replace("{{PRESET}}", config["description"])
494
+ content = content.replace("{{ALLOWED_NUMBERS}}", config["allowed_numbers"])
495
+ content = content.replace("{{MAX_SMALL_INTEGER}}", config["max_small_integer"])
496
+
497
+ return content
498
+
499
+
365
500
  @cli.command("file-placement")
366
501
  @click.argument("paths", nargs=-1, type=click.Path())
367
502
  @click.option("--config", "-c", "config_file", type=click.Path(), help="Path to config file")
@@ -4,7 +4,7 @@ Purpose: Configuration schema for magic numbers linter
4
4
  Scope: MagicNumberConfig dataclass with allowed_numbers and max_small_integer settings
5
5
 
6
6
  Overview: Defines configuration schema for magic numbers linter. Provides MagicNumberConfig dataclass
7
- with allowed_numbers set (default includes common acceptable numbers like 0, 1, 2, -1, 10, 100, 1000)
7
+ with allowed_numbers set (default includes common acceptable numbers like -1, 0, 1, 2, 3, 4, 5, 10, 100, 1000)
8
8
  and max_small_integer threshold (default 10) for range() contexts. Supports per-file and per-directory
9
9
  config overrides through from_dict class method. Validates that configuration values are appropriate
10
10
  types. Integrates with orchestrator's configuration system to allow users to customize allowed numbers
@@ -29,7 +29,9 @@ class MagicNumberConfig:
29
29
  """Configuration for magic numbers linter."""
30
30
 
31
31
  enabled: bool = True
32
- allowed_numbers: set[int | float] = field(default_factory=lambda: {-1, 0, 1, 2, 10, 100, 1000})
32
+ allowed_numbers: set[int | float] = field(
33
+ default_factory=lambda: {-1, 0, 1, 2, 3, 4, 5, 10, 100, 1000}
34
+ )
33
35
  max_small_integer: int = 10
34
36
 
35
37
  def __post_init__(self) -> None:
@@ -54,14 +56,17 @@ class MagicNumberConfig:
54
56
  lang_config = config[language]
55
57
  allowed_numbers = set(
56
58
  lang_config.get(
57
- "allowed_numbers", config.get("allowed_numbers", {-1, 0, 1, 2, 10, 100, 1000})
59
+ "allowed_numbers",
60
+ config.get("allowed_numbers", {-1, 0, 1, 2, 3, 4, 5, 10, 100, 1000}),
58
61
  )
59
62
  )
60
63
  max_small_integer = lang_config.get(
61
64
  "max_small_integer", config.get("max_small_integer", 10)
62
65
  )
63
66
  else:
64
- allowed_numbers = set(config.get("allowed_numbers", {-1, 0, 1, 2, 10, 100, 1000}))
67
+ allowed_numbers = set(
68
+ config.get("allowed_numbers", {-1, 0, 1, 2, 3, 4, 5, 10, 100, 1000})
69
+ )
65
70
  max_small_integer = config.get("max_small_integer", 10)
66
71
 
67
72
  return cls(
@@ -0,0 +1,132 @@
1
+ # thai-lint Configuration File
2
+ # Generated by: thailint init-config
3
+ #
4
+ # For non-interactive mode (AI agents): thailint init-config --non-interactive
5
+ #
6
+ # Full documentation: https://github.com/your-org/thai-lint
7
+
8
+ # ============================================================================
9
+ # MAGIC NUMBERS LINTER
10
+ # ============================================================================
11
+ # Detects unnamed numeric literals that should be extracted as constants
12
+ #
13
+ # Preset: {{PRESET}}
14
+ #
15
+ magic-numbers:
16
+ enabled: true
17
+
18
+ # Numbers that are acceptable without being named constants
19
+ # Default: [-1, 0, 1, 2, 3, 4, 5, 10, 100, 1000]
20
+ allowed_numbers: {{ALLOWED_NUMBERS}}
21
+
22
+ # Maximum integer allowed in range() or enumerate() without flagging
23
+ # Default: 10
24
+ max_small_integer: {{MAX_SMALL_INTEGER}}
25
+
26
+ # -------------------------------------------------------------------------
27
+ # OPTIONAL: Uncomment to add time conversions (lenient mode)
28
+ # -------------------------------------------------------------------------
29
+ # allowed_numbers: [-1, 0, 1, 2, 3, 4, 5, 10, 60, 100, 1000, 3600]
30
+
31
+ # -------------------------------------------------------------------------
32
+ # OPTIONAL: Uncomment to add common HTTP status codes
33
+ # -------------------------------------------------------------------------
34
+ # allowed_numbers: [-1, 0, 1, 2, 3, 4, 5, 10, 100, 200, 201, 204, 400, 401, 403, 404, 500, 502, 503, 1000]
35
+
36
+ # -------------------------------------------------------------------------
37
+ # OPTIONAL: Uncomment to add decimal proportions (0.0-1.0)
38
+ # -------------------------------------------------------------------------
39
+ # allowed_numbers: [-1, 0, 1, 2, 3, 4, 5, 10, 100, 1000, 0.0, 0.1, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.9, 1.0]
40
+
41
+ # ============================================================================
42
+ # NESTING LINTER
43
+ # ============================================================================
44
+ # Checks for excessive nesting depth (if/for/while/try statements)
45
+ #
46
+ nesting:
47
+ enabled: true
48
+
49
+ # Maximum nesting depth allowed
50
+ # Default: 4
51
+ max_nesting_depth: 4
52
+
53
+ # ============================================================================
54
+ # SINGLE RESPONSIBILITY PRINCIPLE (SRP) LINTER
55
+ # ============================================================================
56
+ # Detects classes that may have too many responsibilities
57
+ #
58
+ srp:
59
+ enabled: true
60
+
61
+ # Maximum methods per class
62
+ # Default: 7
63
+ max_methods: 7
64
+
65
+ # Maximum lines of code per class
66
+ # Default: 200
67
+ max_loc: 200
68
+
69
+ # ============================================================================
70
+ # DRY (DON'T REPEAT YOURSELF) LINTER
71
+ # ============================================================================
72
+ # Detects duplicate code blocks
73
+ #
74
+ dry:
75
+ enabled: true
76
+
77
+ # Minimum lines for a block to be considered duplicate
78
+ # Default: 6
79
+ min_duplicate_lines: 6
80
+
81
+ # Enable SQLite caching for faster incremental scans
82
+ # Default: true
83
+ cache_enabled: true
84
+
85
+ # Cache file location (relative to project root)
86
+ # Default: .thailint-cache/dry.db
87
+ cache_path: .thailint-cache/dry.db
88
+
89
+ # ============================================================================
90
+ # FILE PLACEMENT LINTER
91
+ # ============================================================================
92
+ # Ensures files are in appropriate directories
93
+ #
94
+ file-placement:
95
+ enabled: true
96
+
97
+ # Rules for file placement
98
+ rules:
99
+ # Test files should be in tests/ directory
100
+ - pattern: "test_*.py"
101
+ required_dir: "tests/"
102
+ message: "Test files must be in tests/ directory"
103
+
104
+ # Config files should be in config/ or root
105
+ - pattern: "*config*.py"
106
+ required_dir: ["config/", "./"]
107
+ message: "Config files should be in config/ or project root"
108
+
109
+ # ============================================================================
110
+ # GLOBAL SETTINGS
111
+ # ============================================================================
112
+ #
113
+ # Exclude patterns (files/directories to ignore)
114
+ exclude:
115
+ - ".git/"
116
+ - ".venv/"
117
+ - "venv/"
118
+ - "node_modules/"
119
+ - "__pycache__/"
120
+ - "*.pyc"
121
+ - ".pytest_cache/"
122
+ - "dist/"
123
+ - "build/"
124
+ - ".eggs/"
125
+
126
+ # Output format (text or json)
127
+ # Default: text
128
+ output_format: text
129
+
130
+ # Exit with error code if violations found
131
+ # Default: true
132
+ fail_on_violations: true
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes