A utility-first CSS framework for rapid UI development.
This report summarizes scanner evidence for tailwindlabs/tailwindcss, a TypeScript project with 98,033 GitHub stars. SynthScan examined 178,978 lines of code across 478 source files, recording 298 pattern matches distributed across 8 syntactic categories. The legacy adjusted pattern signal is 1.7 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 292 finding(s).
Are imports declared and package/API names verified? 6 finding(s).
Are wrappers, guards, and repeated structures necessary? 67 finding(s).
Which changes need focused human review? 298 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 298 distinct pattern matches across 8 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | crates/ignore/src/overrides.rs | 21 | /// example, if there are one or more whitelist globs and a file path doesn't | COMMENT |
| LOW | crates/ignore/src/overrides.rs | 81 | /// | COMMENT |
| LOW | crates/ignore/src/overrides.rs | 161 | } | COMMENT |
| LOW | crates/ignore/src/types.rs | 101 | /// that matched. | COMMENT |
| LOW | crates/ignore/src/types.rs | 161 | } | COMMENT |
| LOW | crates/ignore/src/pathutil.rs | 1 | use std::{ffi::OsStr, path::Path}; | COMMENT |
| LOW | crates/ignore/src/pathutil.rs | 41 | /// Returns true if and only if this directory entry is considered to be | COMMENT |
| LOW | crates/ignore/src/dir.rs | 1 | // This module provides a data structure, `Ignore`, that connects "directory | COMMENT |
| LOW | crates/ignore/src/dir.rs | 81 | /// Whether to read .gitignore files. | COMMENT |
| LOW | crates/ignore/src/dir.rs | 101 | // ancestors. | COMMENT |
| LOW | crates/ignore/src/dir.rs | 121 | /// parent directories if many paths are being searched. | COMMENT |
| LOW | crates/ignore/src/dir.rs | 141 | /// directory. This is only used for global gitignores or "explicit" | COMMENT |
| LOW | crates/ignore/src/dir.rs | 781 | } | COMMENT |
| LOW | crates/ignore/src/dir.rs | 961 | /// Enables reading `.ignore` files. | COMMENT |
| LOW | crates/ignore/src/dir.rs | 981 | } | COMMENT |
| LOW | crates/ignore/src/dir.rs | 1481 | assert!(err.is_none()); | COMMENT |
| LOW | crates/ignore/src/lib.rs | 101 | }, | COMMENT |
| LOW | crates/ignore/src/lib.rs | 181 | Error::Glob { .. } => false, | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 21 | /// | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 41 | /// | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 81 | #[derive(Clone, Debug)] | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 141 | /// when it is known to be outside this matcher's root. Unlike | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 161 | .normalized_root | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 181 | /// parent directory (`..`) component. Behavior is unspecified when these | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 501 | /// Returns true only when this match corresponds to a directory *and* | COMMENT |
| LOW | crates/ignore/src/incremental.rs | 521 | /// the minimum depth. In this case, callers should continue looking inside | COMMENT |
| LOW | crates/ignore/src/gitignore.rs | 121 | COMMENT | |
| LOW | crates/ignore/src/gitignore.rs | 221 | /// | COMMENT |
| LOW | crates/ignore/src/gitignore.rs | 301 | // A leading ./ is completely superfluous. We also strip it from | COMMENT |
| LOW | crates/ignore/src/gitignore.rs | 561 | /// Toggle whether the globs should be matched case insensitively or not. | COMMENT |
| LOW | crates/ignore/src/gitignore.rs | 581 | /// For example, if this is set then the glob `[abc` will be treated as the | COMMENT |
| LOW | crates/ignore/src/default_types.rs | 1 | /// This list represents the default file types that ripgrep ships with. In | COMMENT |
| LOW | crates/ignore/src/walk.rs | 121 | /// DirEntryInner is the implementation of DirEntry. | COMMENT |
| LOW | crates/ignore/src/walk.rs | 441 | /// | COMMENT |
| LOW | crates/ignore/src/walk.rs | 461 | /// * First, glob overrides are checked. If a path matches a glob override, | COMMENT |
| LOW | crates/ignore/src/walk.rs | 501 | /// The directory that gitignores should be interpreted relative to. | COMMENT |
| LOW | crates/ignore/src/walk.rs | 641 | max_filesize: self.max_filesize, | COMMENT |
| LOW | crates/ignore/src/walk.rs | 661 | /// the paths were added to this builder. Each matcher accepts paths | COMMENT |
| LOW | crates/ignore/src/walk.rs | 781 | /// This has lower precedence than all other sources of ignore rules. | COMMENT |
| LOW | crates/ignore/src/walk.rs | 821 | COMMENT | |
| LOW | crates/ignore/src/walk.rs | 861 | self.ig_builder.types(types); | COMMENT |
| LOW | crates/ignore/src/walk.rs | 921 | /// Git's config file location is `$HOME/.gitconfig`. If `$HOME/.gitconfig` | COMMENT |
| LOW | crates/ignore/src/walk.rs | 941 | } | COMMENT |
| LOW | crates/ignore/src/walk.rs | 981 | /// | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1001 | /// paths in sorted order. The compare function will be called to compare | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1021 | /// | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1041 | pub fn skip_stdout(&mut self, yes: bool) -> &mut WalkBuilder { | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1441 | impl WalkParallel { | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1461 | /// by implementing `Drop` for your builder (or for your visitor, if you | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1561 | } | COMMENT |
| LOW | crates/ignore/src/walk.rs | 1741 | /// A work-stealing stack of work to do. | COMMENT |
| LOW | crates/oxide/tests/scanner.rs | 61 | COMMENT | |
| LOW | crates/oxide/src/glob.rs | 61 | pattern, | COMMENT |
| LOW | crates/oxide/src/glob.rs | 81 | /// This means, that the following command: | COMMENT |
| LOW | crates/oxide/src/glob.rs | 141 | // | COMMENT |
| LOW | crates/oxide/src/extractor/string_machine.rs | 1 | use crate::cursor; | COMMENT |
| LOW | crates/oxide/src/extractor/candidate_machine.rs | 41 | // Candidates don't start with these characters, so we can skip ahead. | COMMENT |
| LOW | crates/oxide/src/extractor/modifier_machine.rs | 1 | use crate::cursor; | COMMENT |
| LOW | crates/oxide/src/extractor/modifier_machine.rs | 41 | match cursor.curr().into() { | COMMENT |
| LOW | …ates/oxide/src/extractor/arbitrary_variable_machine.rs | 21 | /// Currently parsing the data type of the arbitrary variable | COMMENT |
| 155 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | integrations/utils.ts | 599 | async function overwriteVersionsInPackageJson(content: string): Promise<string> { | CODE |
| LOW | integrations/utils.ts | 615 | function overwriteVersionsInPnpmWorkspace(content: string): string { | CODE |
| LOW | packages/@tailwindcss-cli/src/utils/test-helpers.ts | 3 | export function normalizeWindowsSeparators(p: string) { | CODE |
| LOW | …es/@tailwindcss-cli/src/commands/canonicalize/index.ts | 340 | function createCandidateGroupResult( | CODE |
| LOW | packages/@tailwindcss-node/src/compile.ts | 66 | async function ensureSourceDetectionRootExists(compiler: { | CODE |
| LOW | packages/tailwindcss/src/utilities.ts | 2743 | function resolveInterpolationModifier(modifier: CandidateModifier | null) { | CODE |
| LOW | packages/tailwindcss/src/utilities.ts | 6620 | function alphaReplacedShadowProperties( | CODE |
| LOW | packages/tailwindcss/src/utilities.ts | 6666 | function alphaReplacedDropShadowProperties( | CODE |
| LOW | packages/tailwindcss/src/utilities.ts | 6820 | export function isValidFunctionalUtilityName(name: string): boolean { | CODE |
| LOW | packages/tailwindcss/src/candidate.ts | 1179 | function recursivelyEscapeUnderscores(ast: ValueParser.ValueAstNode[]) { | CODE |
| LOW | packages/tailwindcss/src/candidate.ts | 1244 | function decodeValidArbitraryValue(raw: string): string | null { | CODE |
| LOW | packages/tailwindcss/src/ast.ts | 1428 | function substituteNestingSelector(selector: string, parentSelector: string): string { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 115 | export function prepareDesignSystemStorage( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 142 | function createSignatureOptionsCache(): DesignSystem['storage'][typeof SIGNATURE_OPTIONS_KEY] { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 151 | function createSignatureComparison(designSystem: DesignSystem) { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 183 | function createInternalOptionsCache( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 193 | function createCanonicalizeOptions( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 611 | function createCanonicalizeCandidateCache(): DesignSystem['storage'][typeof CANONICALIZE_CANDIDATE_KEY] { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 687 | function createCanonicalizeVariantCache(): DesignSystem['storage'][typeof CANONICALIZE_VARIANT_KEY] { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 728 | function createCanonicalizeUtilityCache(): DesignSystem['storage'][typeof CANONICALIZE_UTILITY_KEY] { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 848 | function spacingCalcToSpacingFunction(input: string, designSystem: DesignSystem) { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 1080 | function substituteFunctionsInValue( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 1736 | function arbitraryValueToBareValueUtility( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 1762 | function arbitraryValueToBareValueVariant(variant: Variant): Variant | Variant[] { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 1909 | function modernizeArbitraryValuesVariant( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2330 | function optimizeArbitraryValueExpressions( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2530 | function createUtilitySignatureCache( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2562 | function createUtilityThemeVariablesCache( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2585 | function compileUtilitySignatureAst( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2908 | function createStaticUtilitiesCache(): DesignSystem['storage'][typeof STATIC_UTILITIES_KEY] { | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2919 | function createUtilityPropertiesCache( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 2962 | function createPreComputedUtilitiesCache( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 3023 | function createVariantSignatureCache( | CODE |
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 3134 | function createPreComputedVariantsCache( | CODE |
| LOW | …kages/tailwindcss/src/canonicalize-calc-expressions.ts | 7 | export function canonicalizeCalcExpressions(input: string): string { | CODE |
| LOW | …kages/tailwindcss/src/canonicalize-calc-expressions.ts | 13 | export function canonicalizeCalcExpressionsAst( | CODE |
| LOW | packages/tailwindcss/src/constant-fold-declaration.ts | 18 | export function constantFoldDeclarationAst( | CODE |
| LOW | packages/tailwindcss/src/css-functions.ts | 204 | export function substituteFunctionsInValue( | CODE |
| LOW | packages/tailwindcss/src/css-functions.ts | 245 | function injectFallbackForInitialFallback(ast: ValueParser.ValueAstNode[], fallback: string): void { | CODE |
| LOW | packages/tailwindcss/src/variants.ts | 1006 | function compareBreakpointVariants( | CODE |
| LOW | packages/tailwindcss/src/compat/plugin-api.ts | 640 | function replaceNestedClassNameReferences( | CODE |
| LOW | packages/tailwindcss/src/compat/theme-variants.ts | 4 | export function registerThemeVariantOverrides(config: ResolvedConfig, designSystem: DesignSystem) { | CODE |
| LOW | packages/tailwindcss/src/compat/container.ts | 22 | export function buildCustomContainerUtilityRules( | CODE |
| LOW | packages/tailwindcss/src/compat/apply-compat-hooks.ts | 229 | function upgradeToFullPluginSupport({ | CODE |
| LOW | packages/tailwindcss/src/utils/math-operators.ts | 45 | export function addWhitespaceAroundMathOperators(input: string) { | CODE |
| LOW | …ckages/tailwindcss/src/utils/decode-arbitrary-value.ts | 23 | function convertUnderscoresToWhitespace(input: string, skipUnderscoreToSpace = false) { | CODE |
| LOW | …ckages/tailwindcss/src/utils/decode-arbitrary-value.ts | 48 | function recursivelyDecodeArbitraryValues(ast: ValueParser.ValueAstNode[]) { | CODE |
| LOW | …es/tailwindcss/src/source-maps/visualize-source-map.ts | 101 | function buildAnnotationsFromSourceMapPoints(points: SourceMapPoint[]) { | CODE |
| LOW | …es/tailwindcss/src/source-maps/visualize-source-map.ts | 460 | function visualizeSourceRangeContinuation( | CODE |
| LOW | …es/tailwindcss/src/source-maps/visualize-source-map.ts | 480 | function visualizeGeneratedRangeContinuation( | CODE |
| LOW | …es/tailwindcss/src/source-maps/visualize-source-map.ts | 508 | function visualizeContinuationRange(range: Range, label: string, line: string, lineNumber: number) { | CODE |
| LOW | packages/@tailwindcss-vite/src/index.ts | 123 | function createBackCompatIdResolver( | CODE |
| LOW | …lwindcss-upgrade/src/codemods/css/migrate-preflight.ts | 117 | function substituteFunctionsInValue( | CODE |
| LOW | …pgrade/src/codemods/css/migrate-tailwind-directives.ts | 5 | export function migrateTailwindDirectives(options: { newPrefix: string | null }): Plugin { | CODE |
| LOW | …windcss-upgrade/src/codemods/config/migrate-postcss.ts | 148 | function isTailwindCSSNestingPlugin(line: string) { | CODE |
| LOW | …windcss-upgrade/src/codemods/config/migrate-postcss.ts | 230 | function isTailwindCSSNestingPlugin(plugin: string, options: any) { | CODE |
| LOW | …ndcss-upgrade/src/codemods/config/migrate-js-config.ts | 516 | function removeUnnecessarySpacingKeys( | CODE |
| LOW | …-upgrade/src/codemods/template/migrate-theme-to-var.ts | 172 | function substituteFunctionsInValue( | CODE |
| LOW | …rc/codemods/template/migrate-canonicalize-candidate.ts | 16 | export function migrateCanonicalizeCandidate( | CODE |
| LOW | …c/codemods/template/migrate-legacy-arbitrary-values.ts | 6 | export function migrateLegacyArbitraryValues( | CODE |
| 7 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | packages/tailwindcss/src/utilities.test.ts | 31537 | // This originated from a bug. Essentially in the second `--mask-right` we | COMMENT |
| MEDIUM | packages/tailwindcss/src/ast.ts | 880 | // for a given rule. This also means that we can leverage CSS nesting | COMMENT |
| MEDIUM | packages/tailwindcss/src/canonicalize-candidates.ts | 2707 | // Essentially normalizing the `node.value` to a canonical form. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | packages/tailwindcss/src/utilities.ts | 4102 | colorUtility('placeholder', { | CODE |
| LOW | packages/tailwindcss/src/utilities.test.ts | 23445 | test('placeholder', async () => { | CODE |
| LOW | packages/tailwindcss/src/utilities.test.ts | 23593 | 'placeholder', | CODE |
| LOW | packages/tailwindcss/src/variants.test.ts | 101 | test('placeholder', async () => { | CODE |
| LOW | packages/tailwindcss/src/variants.ts | 701 | staticVariant('placeholder', ['&::placeholder']) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | packages/@tailwindcss-upgrade/src/utils/renderer.ts | 105 | print() | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | crates/ignore/src/gitignore.rs | 222 | /// NOTE: This method is more expensive than walking the directory hierarchy | COMMENT |
| LOW | packages/@tailwindcss-vite/src/index.ts | 179 | // Step 1: Scan source files for candidates | COMMENT |
| LOW | …kages/@tailwindcss-upgrade/src/codemods/css/analyze.ts | 44 | // Step 1: Record which `@import` rules point to which stylesheets | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | packages/tailwindcss/src/canonicalize-candidates.ts | 1517 | // We need to check if the variable is used in the replacement | COMMENT |
| LOW | packages/@tailwindcss-vite/src/index.ts | 179 | // Step 1: Scan source files for candidates | COMMENT |
| LOW | …kages/@tailwindcss-upgrade/src/codemods/css/analyze.ts | 44 | // Step 1: Record which `@import` rules point to which stylesheets | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | crates/classification-macros/src/lib.rs | 14 | /// Example usage: | COMMENT |