console.log in one language, fmt.Println in another, and print() in a third. A third-party import looks completely different in go.mod and requirements.txt. Analysis that doesn’t know which language it’s reading ends up counting lines and tokens, which tells you nothing.
Don’t compare scores across languages. A TypeScript file carries deductions that simply don’t exist in Go, Python, Ruby, C#, Java, or Rust:
any, @ts-ignore, missing return types, non-null assertions. An 80 in Go and an 80 in TypeScript are not the same 80, and ranking a mixed codebase by score across languages will mislead you.- TypeScript & JavaScript
- Vue & Svelte
- Go
- Python
- Ruby
- C#
- Java
- Rust
Iris Code scans
.js, .jsx, .mjs, .cjs, .ts, and .tsx files with a single TS/JS parser. All six extensions are treated as the same language family and share the same rule set.TypeScript / JavaScript-specific features:- Unused import detection - named, default, and namespace bindings that are imported but never referenced in the file are flagged as unused imports. This detection is TS/JS only - Go and Python handle unused imports at the compiler or runtime level.
- TypeScript quality metrics -
anyusages,@ts-ignoresuppressions, non-null assertions (!), and exported functions missing a return type annotation are surfaced as separate counters in the File tab. See TypeScript Metrics for the full breakdown. - Debug prints -
console.log,console.warn, andconsole.errorcalls are flagged in Code Lens and in the Code Smells section.
Iris Code analyses
.vue and .svelte single-file components by extracting their script blocks and running them through the same TS/JS analyser as an ordinary module. There is nothing to configure and no plugin to install.- Script blocks only - Vue
<script>and<script setup>, and Svelte instance and module<script>blocks, are analysed.<template>, Svelte markup, and<style>are excluded from analysis and from duplicate detection, so component markup never inflates a finding count or a duplication percentage. - Original line numbers - every finding,
iris-ignoresuppression, and duplicate range reports the line you see in your own component file. A secret on line 11 of a.vuefile is reported at line 11. langdecides the rule set - a component whose script declareslang="ts"(orlang="typescript") is analysed as TypeScript, so TypeScript quality metrics apply. Any other component is analysed as JavaScript. An unrecognised preprocessor (for examplelang="coffee") is skipped rather than mis-parsed.- Root-level scripts only - a
<script>tag nested inside<template>,<svelte:head>, or a Svelte{#if}block is rendered markup, not executable code, and is not analysed. - Framework file names are respected - SvelteKit route files (
+page.svelte,+layout.svelte,+server.tsand siblings) are exempt from file-naming conventions, because the framework resolves them by exact name. - Role-aware file naming - a component still resolves to the
typescriptorjavascriptlanguage key from its script tag for thresholds and scoring. Naming can additionally use ordered path globs, socomponents/CheckoutPanel.vuecan requirePascalCasewhilecomposables/useCart.tsrequirescamelCase, even though both contain TypeScript. See File naming conventions.
Iris Code parses
.go files with a Go-specific analyser. Language-aware behaviours include:- Function detection - both top-level functions (
func Name() and methods (func (r *T) Name() are detected and listed with line numbers - Third-party imports - packages are identified as third-party when their root path segment contains a dot (e.g.
golang.org/x/...,pkg.example.com/...) - Debug prints -
fmt.Print*,log.Print*,log.Fatal*, andlog.Panic*calls are flagged in Code Lens and in the Code Smells section; controlled by theenableConsoleLogWarningstoggle - No-exports warning - Iris Code raises a warning if no capitalised (exported) function names are found in the file
- Unused Go modules - a workspace scan reads
go.modand flags any declared module that is never imported across.gofiles in the project vendor/directory - skipped automatically during workspace and folder scans
Iris Code parses
.py files with a Python-specific analyser. Language-aware behaviours include:- Function detection - all
defdeclarations are detected, including top-level functions and class methods, each listed with its line number - Third-party imports -
import pkgandfrom pkg import ...are evaluated; stdlib modules are excluded automatically so only genuine third-party packages appear - Debug prints -
print()calls are flagged in Code Lens and in the Code Smells section; controlled by theenableConsoleLogWarningstoggle - No public functions warning - Iris Code raises a warning if every function in the file starts with
_(private by convention), indicating no public API is exposed - Unused Python packages - a workspace scan reads
requirements.txtandpyproject.tomland flags any declared package that is never imported across.pyfiles in the project - Auto-skipped directories -
__pycache__,.venv, andvenvdirectories are skipped automatically during workspace and folder scans - Parameter counting -
selfandclsare excluded from the parameter count when evaluating long parameter list warnings
Ruby spreads itself across more filenames than most languages: a
Gemfile has no extension, a Rake task uses .rake, and a Rails view is Ruby embedded in HTML. Iris Code recognises all three rather than only scanning .rb.Files that are analysed:.rb, .rbw, .rake, .gemspec, .ru, .thor, .builder, .jbuilder, .rabl, .arb, .podspec, .erb, and .rhtml.Extensionless files are matched by name: Gemfile, Rakefile, Vagrantfile, Capfile, Guardfile, Podfile, Brewfile, Berksfile, Puppetfile, Thorfile, Dangerfile, the Fastlane set (Fastfile, Appfile, Matchfile, Gymfile, Scanfile, Snapfile, Deliverfile, Pluginfile), and the .irbrc and .pryrc dotfiles.Language-aware behaviours:- Method detection - instance methods, class methods (
def self.name), operator methods, and endless methods (def total = items.sum) are all detected. A method’s end is resolved by trackingdo/endblock nesting, so a method containing blocks is measured at its real length rather than ending at the firstend. - Heredocs, percent literals, and comments - heredoc bodies (including squiggly
<<~),%w[]and%i[]literals,#comments, and=begin/=endblocks are excluded before pattern matching, so aputsquoted inside a heredoc is not counted as a live debug print. - Gems and requires -
requireandautoloadcalls are read as imports, and aGemfileor.gemspeccontributes its declared gems. Standard-library requires are excluded so only genuine third-party dependencies count towards the import threshold. - Debug prints -
puts,print,p, andppat the start of a statement are flagged, controlled by theenableConsoleLogWarningstoggle. method_missingwithoutrespond_to_missing?- defining one without the other leavesrespond_to?and reflection lying about what the object answers to. Iris Code flags the pair as incomplete.- God classes - a class defining more methods than the configured limit is flagged at its
classline, with the class name and method count. - Rails mass assignment - parameters passed straight into a model without
requireandpermitare flagged as an error, because the vulnerability is in what the code omits rather than in anything visible on the line. - ERB templates -
.erband.rhtmlfiles have their Ruby extracted from<% %>and<%= %>tags; the surrounding HTML is excluded from analysis and from duplicate detection. Findings report the line number in the template file itself, so a secret on line 14 of a view is reported at line 14.
iris-ignore suppressions, gate rules, and per-language languages.ruby overrides all apply to Ruby the same way they apply to every other language.No unused-code detection in Ruby. Ruby resolves methods and constants at runtime, so a constant referenced only through
send, const_get, or a Rails autoload is invisible to static analysis. Iris Code reports no unused imports or unused gems for Ruby rather than reporting ones it cannot stand behind. Dependency and CVE scanning does cover RubyGems when versions can be pinned from Gemfile.lock; unpinned Gemfile-only entries are reported as not checked rather than clean.Iris Code reads
.cs source files and .csproj project files. The project file is treated as a manifest rather than as code: it contributes the packages your project depends on and it is scanned for secrets, but its language version and warning level are build settings, not unnamed numbers in a method.Language-aware behaviours:- Method detection - methods, constructors, expression-bodied members and local functions are detected, including constructors that chain through a
: base(...)or: this(...)initialiser. A positionalrecordis counted once, as a type. - Namespaces and packages -
using,global using,using staticand aliasedusingdirectives are read as imports.System.*is excluded, because the base class library appears in every file and tells you nothing about coupling.Microsoft.*is counted: EF Core, ASP.NET Core and the Extensions packages are third-party dependencies like any other. A.csprojcontributes itsPackageReferenceentries;FrameworkReferenceentries that name the .NET runtime itself are excluded. - String literals - all five C# string forms are understood before any rule runs: regular, verbatim (
@"C:\logs\"), interpolated ($"...",$@"..."), raw ("""...""", at any delimiter length) and char literals. A Windows path or a JSON payload inside a literal cannot be mistaken for code. - Debug output -
Console.Write*,Debug.Write*andTrace.Write*calls are flagged in Code Lens and in the Code Smells section, controlled by theenableConsoleLogWarningstoggle. async void- a method that returnsvoidinstead ofTaskgives the caller nothing to await and nothing to catch, so a thrown exception takes the process down. Iris Code flags it as an error, and exempts event handlers (On*,*Handler,*_Clickand siblings), where the framework requires that signature.- Catch-all exception handlers -
catch (Exception ex),catch (Exception)and a barecatchare flagged. Awhen (...)filter is deliberate, targeted handling and is exempt. - LINQ chain length - five or more LINQ operators in one statement is flagged. The count is per statement, not per line, because an idiomatic chain is written one operator per line.
- Large types - a class, record or struct carrying more methods than the configured limit, or spanning more lines than
fileLengthThreshold, is flagged at its declaration line with its name and method count. - Nesting - depth is measured from the method’s own opening brace, so a method written in Allman style measures the same as the identical method written with the brace on the signature line.
- Test projects - C# has no filename separator for tests, so
OrdersControllerTests.cs,OrderSpec.csand anything inside a<Project>.Tests,.IntegrationTestsor.UnitTestsdirectory are recognised as tests. Fixture credentials andlocalhostURLs there are not reported as production findings. - Renaming - a rename does not update type names, namespaces, or project references. Iris Code warns you when a
.csfile is renamed.
iris-ignore suppressions, gate rules, and per-language languages.csharp overrides all apply to C# the same way they apply to every other language. Secrets are read from string and var declarations, from property initialisers, and from project XML: <UserSecretsId> and MSBuild references such as $(ApiTokenFromCi) are the correct way to keep a credential out of the repository, and are never flagged.No unused-code detection in C#. Dependency injection, reflection, partial classes and source generators all reference code in ways static analysis cannot see, so Iris Code reports no unused members or unused packages for C# rather than reporting ones it cannot stand behind. NuGet dependency and CVE scanning is available through the dependency table; projects without
packages.lock.json expose direct package declarations only.Iris Code reads
.java source files and .properties configuration. The properties file is treated as a manifest rather than as code: it is scanned for committed credentials, but its port numbers and log levels are settings, not unnamed numbers in a method.Language-aware behaviours:- Method detection - methods and constructors are detected, including generic signatures,
throwsclauses, and members collapsed onto a single line. A type written entirely on one line still reports its methods, so it is not silently exempt from the length, parameter, and nesting rules. - Text blocks and unicode escapes - both are understood before any rule runs. A text block (
"""...""") holding JSON does not leak its braces into the structure of the file, and a\uXXXXescape is decoded the way javac decodes it, before tokenising, so an escaped quote is a real string delimiter wherever it appears. - Imports -
importandimport staticare read as imports.java.*andjavax.*are excluded, because the platform appears in nearly every file and tells you nothing about coupling. Everything else counts, including Spring and the rest of your dependency tree. - Unused import detection - Java is one of the few languages where this verdict is safe: an import is a compile-time type alias, there is no extension-method equivalent, and javac itself warns. The check reads Javadoc, so an import referenced only from a
{@link Foo}is left alone, because deleting it would breakjavadoc. Wildcard imports cannot be judged and are skipped rather than guessed at. - Debug output -
System.out.print*andSystem.err.print*calls are flagged in Code Lens and in the Code Smells section, controlled by theenableConsoleLogWarningstoggle. - Catch-all exception handlers -
catch (Exception e)andcatch (Throwable t)are flagged, including the fully-qualifiedjava.lang.forms and a multi-catch ending in one of them. A narrowly typed catch is deliberate handling and is not flagged. This is the same rule id C# uses, so one severity setting and oneiris-ignorecomment cover a codebase using both. - Process execution -
Runtime.getRuntime().execandProcessBuilderare flagged, prompting you to validate every argument. This is deliberately separate from dynamic code evaluation, which Java does not have in the sense that rule means. - Test source sets - Gradle lets a project declare any number of test source sets, and the convention is a
Test-suffixed name.src/test,src/integTest,src/javaRestTest,src/internalClusterTest,src/testFixturesand their siblings are all recognised, as are*Tests.java,*TestCase.java, and Maven’s failsafe*IT.javaconvention. Fixture credentials andlocalhostURLs there are not reported as production findings. - Framework-reserved file names -
application.properties,application-dev.properties, andmessages.propertiesare exempt from file-naming conventions, because Spring andResourceBundleresolve them by exact filename. Renaming them would break the application.
iris-ignore suppressions, gate rules, and per-language languages.java overrides all apply to Java the same way they apply to every other language. Credentials are read from field and local declarations, from setter calls such as setPassword("..."), from Properties.put entries, and from .properties keys. A committed spring.datasource.password is the most common Java credential leak and has no recognisable token format, so the name-based check is what catches it.Iris Code parses
.rs files with a Rust-specific analyser, and reads Cargo.lock for dependency analysis.Language-aware behaviours:- Function detection - free functions, associated functions, and trait implementations are detected, including
pub,async,const,unsafe, andextern "C"forms, plus generic parameters and where clauses. A trait method declaration with no body is not counted as a function. - Lifetimes are not char literals -
&'a stris a reference, and a scanner treating the apostrophe as an opening quote would blank real code up to the next one. Lifetimes appear throughout non-trivial Rust, so this is the common case rather than an edge one, and it is handled before any rule runs. - Raw strings, nested comments, and raw identifiers - raw strings at any hash depth (
r#"..."#), byte strings, nested block comments (which Rust allows and C does not), and raw identifiers (r#typeis an identifier, not a string) are all understood. unwrapandexpect- flagged as unhandled error paths, prompting?or a match instead.- Explicit panics -
panic!,todo!, andunimplemented!are flagged separately fromunwrap, because the fix differs: one is an unhandled error, the other a deliberate abort. - Inline test modules are exempt - this has no equivalent in any other supported language. Rust puts tests inside the file under test, so the exemption is computed per
#[cfg(test)]and#[test]item rather than per file. A whole-file exemption would either spare the production half too or spare nothing, and without itunwrapdensity floods every well-tested file. Fixture credentials inside a test module are exempt for the same reason. - Debug output -
println!,eprintln!,print!,eprint!, anddbg!are flagged, controlled by theenableConsoleLogWarningstoggle. - Imports -
usedeclarations are counted, including nested groups such asuse crate::{ui::{Button, Panel}, theme}.std,core, andallocare excluded as the standard library, andcrate,self, andsuperas internal paths. - Test and benchmark directories -
tests/,benches/, andexamples/are Cargo conventions and are treated as test code.
iris-ignore suppressions, gate rules, and per-language languages.rust overrides all apply to Rust the same way they apply to every other language. Credentials are read from let, const, and static bindings and from struct literal fields, which is how Rust configuration is usually written.No unused-import detection in Rust. A trait must be imported for its methods to be callable, and its name is then never written again:
use gpui::Styled; is what makes .bg(...) compile. That usage is invisible to static analysis and rustc does not warn about it, so Iris Code reports no unused imports for Rust rather than reporting ones it cannot stand behind. Measured against a real Rust codebase, the check produced roughly three findings per file and nearly all of them were correct code. Cargo dependency and CVE scanning is available through the dependency table, and Cargo.lock gives the full resolved transitive tree.