Skip to content

Commit 2e95b5f

Browse files
Solomonclaude
andcommitted
fix(ego-lint): auto-detect and exclude vendored files from all lint checks
Files with third-party attribution headers (@license, @generated, Credits: <URL>, Adapted from <URL>) in the first 30 comment lines are now auto-detected as vendored and excluded from: - All Tier 1 pattern rules (apply-patterns.py) - quality/module-state and all Tier 2 quality checks (check-quality.py) This eliminates ~79 noisy warnings from forge's lib/css/index.js (a vendored reworkcss/css parser) and lib/prefs/widgets.js (aylur widget library), reducing pattern-rule WARNs from 115 → 36 on forge. Also adds per-rule exclude-files support (glob patterns relative to ext_dir) in apply-patterns.py for targeted explicit exclusions. Detection is zero-config: no .egoignore file required. A SKIP notice is emitted listing all auto-detected vendored files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent f4b480f commit 2e95b5f

File tree

7 files changed

+151
-2
lines changed

7 files changed

+151
-2
lines changed

skills/ego-lint/scripts/apply-patterns.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,56 @@ def validate_rules(rules_file):
252252
return 0
253253

254254

255+
# Patterns that signal a file is vendored/third-party code (checked in first 30 lines).
256+
# Each pattern is matched against comment lines (lines starting with // or * or /*)
257+
_VENDORED_SIGNALS = re.compile(
258+
r'(@license\b'
259+
r'|@generated\b'
260+
r'|@auto-generated\b'
261+
r'|Credits:\s*https?://'
262+
r'|Adapted from\s+https?://'
263+
r')',
264+
re.IGNORECASE,
265+
)
266+
_COMMENT_LINE = re.compile(r'^\s*(//|/?\*)')
267+
268+
269+
def _is_vendored_file(filepath, scan_lines=30):
270+
"""Return True if the file appears to be vendored/third-party code.
271+
272+
Reads the first *scan_lines* lines and looks for common attribution
273+
patterns that indicate the file was copied from an external source:
274+
@license, @generated, Credits:, Adapted from. Only matches inside
275+
comment lines to avoid false positives in code strings.
276+
"""
277+
try:
278+
with open(filepath, encoding='utf-8', errors='replace') as f:
279+
for i, line in enumerate(f):
280+
if i >= scan_lines:
281+
break
282+
if _COMMENT_LINE.match(line) and _VENDORED_SIGNALS.search(line):
283+
return True
284+
except OSError:
285+
pass
286+
return False
287+
288+
289+
def _discover_vendored_files(ext_dir):
290+
"""Scan all JS files in ext_dir and return a set of relative paths that
291+
appear to be vendored third-party code."""
292+
vendored = set()
293+
skip_dirs = ('node_modules', '.git', '__pycache__')
294+
for filepath in glob.glob(os.path.join(ext_dir, '**', '*.js'), recursive=True):
295+
if not os.path.isfile(filepath):
296+
continue
297+
rel = os.path.relpath(filepath, ext_dir)
298+
if any(part in skip_dirs for part in rel.split(os.sep)):
299+
continue
300+
if _is_vendored_file(filepath):
301+
vendored.add(rel.replace(os.sep, '/'))
302+
return vendored
303+
304+
255305
def main():
256306
# Handle --validate mode
257307
if len(sys.argv) >= 3 and sys.argv[1] == '--validate':
@@ -273,6 +323,13 @@ def main():
273323
min_shell = min(shell_versions) if shell_versions else None
274324
is_compiled_ts = os.environ.get('EGO_LINT_COMPILED_TS') == '1'
275325

326+
# Pre-scan: identify vendored files once and reuse across all rules
327+
vendored_files = _discover_vendored_files(ext_dir)
328+
if vendored_files:
329+
files_list = ', '.join(sorted(vendored_files))
330+
print(f"SKIP|vendored-file-exclusion|{len(vendored_files)} file(s) auto-detected as "
331+
f"vendored (third-party attribution header); excluded from pattern rules: {files_list}")
332+
276333
for rule in rules:
277334
rid = rule.get('id', '?')
278335
pattern = rule.get('pattern', '')
@@ -307,6 +364,15 @@ def main():
307364
found = False
308365
dedup_files = set() # For deduplicate mode
309366
exclude_dirs = set(rule.get('exclude-dirs', []))
367+
# exclude-files: list of glob patterns (relative to ext_dir) for per-rule exclusions
368+
exclude_files_patterns = rule.get('exclude-files', [])
369+
if isinstance(exclude_files_patterns, str):
370+
exclude_files_patterns = [exclude_files_patterns]
371+
# Expand exclude-files globs once per rule
372+
exclude_files_set = set()
373+
for efpat in exclude_files_patterns:
374+
for match in glob.glob(os.path.join(ext_dir, efpat), recursive=True):
375+
exclude_files_set.add(os.path.realpath(match))
310376

311377
try:
312378
compiled = re.compile(pattern)
@@ -345,6 +411,13 @@ def main():
345411
rel_parts = rel.replace(os.sep, '/').split('/')
346412
if rel_parts[0] in exclude_dirs:
347413
continue
414+
# Skip auto-detected vendored files
415+
rel_posix = rel.replace(os.sep, '/')
416+
if rel_posix in vendored_files:
417+
continue
418+
# Skip per-rule excluded files
419+
if exclude_files_set and os.path.realpath(filepath) in exclude_files_set:
420+
continue
348421
seen.add(filepath)
349422
try:
350423
with open(filepath, encoding='utf-8', errors='replace') as f:

skills/ego-lint/scripts/check-quality.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,48 @@ def is_suppressed(line, check_name, prev_line=''):
3838
return False
3939

4040

41+
_VENDORED_SIGNALS = re.compile(
42+
r'(@license\b'
43+
r'|@generated\b'
44+
r'|@auto-generated\b'
45+
r'|Credits:\s*https?://'
46+
r'|Adapted from\s+https?://'
47+
r')',
48+
re.IGNORECASE,
49+
)
50+
_COMMENT_LINE = re.compile(r'^\s*(//|/?\*)')
51+
52+
53+
def _is_vendored_file(filepath, scan_lines=30):
54+
"""Return True if the file appears to be vendored/third-party code.
55+
56+
Reads the first *scan_lines* lines and looks for common attribution
57+
patterns: @license, @generated, Credits:, Adapted from.
58+
Only matches inside comment lines to avoid false positives.
59+
"""
60+
try:
61+
with open(filepath, encoding='utf-8', errors='replace') as f:
62+
for i, line in enumerate(f):
63+
if i >= scan_lines:
64+
break
65+
if _COMMENT_LINE.match(line) and _VENDORED_SIGNALS.search(line):
66+
return True
67+
except OSError:
68+
pass
69+
return False
70+
71+
4172
def find_js_files(ext_dir):
42-
"""Find all JS files in extension directory, excluding node_modules."""
73+
"""Find all JS files in extension directory, excluding node_modules and vendored files."""
4374
skip_dirs = {'node_modules', '.git', '__pycache__'}
4475
files = []
4576
for root, dirs, filenames in os.walk(ext_dir):
4677
dirs[:] = [d for d in dirs if d not in skip_dirs]
4778
for name in filenames:
4879
if name.endswith('.js'):
49-
files.append(os.path.join(root, name))
80+
filepath = os.path.join(root, name)
81+
if not _is_vendored_file(filepath):
82+
files.append(filepath)
5083
return files
5184

5285

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Vendored file exclusion tests
2+
# Sourced by run-tests.sh — uses run_lint, assert_output_contains, assert_exit_code, etc.
3+
#
4+
# Verifies that files with third-party attribution headers (@license, Credits:, etc.)
5+
# are auto-detected as vendored and excluded from pattern rules and quality checks.
6+
7+
echo "=== vendored-exclusion ==="
8+
run_lint "vendored-exclusion@test"
9+
assert_exit_code "exits with 0 (vendored file not flagged)" 0
10+
# Pattern rules must skip vendored file
11+
assert_output_not_contains "no R-DEPR-09 (var) from vendored file" "\[WARN\].*R-DEPR-09.*css-parser"
12+
# Quality module-state must skip vendored file
13+
assert_output_not_contains "no quality/module-state from vendored file" "\[WARN\].*quality/module-state.*css-parser"
14+
# SKIP notice must be emitted
15+
assert_output_contains "vendored-file-exclusion SKIP emitted" "\[SKIP\].*vendored-file-exclusion"
16+
echo ""
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MIT License
2+
Copyright (c) 2024 Test Author
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
2+
3+
export default class VendoredExclusionExtension extends Extension {
4+
enable() {}
5+
disable() {}
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Credits: https://github.com/reworkcss/css/tree/master/lib/parse
2+
// Licensed under MIT
3+
4+
// This is a vendored CSS parser. Uses ES5-style var declarations
5+
// that would normally trigger R-DEPR-09 warnings:
6+
var lineno = 1;
7+
var column = 1;
8+
9+
export function parse(css) {
10+
var result = {};
11+
return result;
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"uuid": "vendored-exclusion@test",
3+
"name": "Vendored File Exclusion Test",
4+
"description": "Tests that vendored/third-party files are excluded from pattern rules",
5+
"shell-version": ["45"],
6+
"url": "https://example.com"
7+
}

0 commit comments

Comments
 (0)