@aiready/consistency 0.18.15 → 0.18.17

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.
@@ -1,203 +0,0 @@
1
- /**
2
- * Python Naming Analyzer - PEP 8 Compliant
3
- *
4
- * Analyzes Python code for PEP 8 naming convention violations
5
- * https://peps.python.org/pep-0008/#naming-conventions
6
- */
7
-
8
- import { getParser, Severity } from '@aiready/core';
9
- import type { NamingIssue } from '../types';
10
-
11
- /**
12
- * Analyze Python files for PEP 8 naming violations
13
- */
14
- export async function analyzePythonNaming(
15
- files: string[]
16
- ): Promise<NamingIssue[]> {
17
- const issues: NamingIssue[] = [];
18
- const parser = getParser('dummy.py'); // Get Python parser instance
19
-
20
- if (!parser) {
21
- console.warn('Python parser not available');
22
- return issues;
23
- }
24
-
25
- // Filter to only Python files
26
- const pythonFiles = files.filter((f) => f.toLowerCase().endsWith('.py'));
27
-
28
- for (const file of pythonFiles) {
29
- try {
30
- const fs = await import('fs');
31
- const code = await fs.promises.readFile(file, 'utf-8');
32
- const result = parser.parse(code, file);
33
-
34
- // Analyze each export for naming violations
35
- for (const exp of result.exports) {
36
- const nameIssue = checkPythonNaming(
37
- exp.name,
38
- exp.type,
39
- file,
40
- exp.loc?.start.line || 0
41
- );
42
- if (nameIssue) {
43
- issues.push(nameIssue);
44
- }
45
- }
46
-
47
- // Analyze imports for naming issues (optional, less critical)
48
- for (const imp of result.imports) {
49
- for (const spec of imp.specifiers) {
50
- if (spec !== '*' && spec !== 'default') {
51
- const nameIssue = checkPythonNaming(
52
- spec,
53
- 'variable',
54
- file,
55
- imp.loc?.start.line || 0
56
- );
57
- if (nameIssue) {
58
- issues.push(nameIssue);
59
- }
60
- }
61
- }
62
- }
63
- } catch (error) {
64
- console.warn(`Skipping ${file} due to error:`, error);
65
- }
66
- }
67
-
68
- return issues;
69
- }
70
-
71
- /**
72
- * Check a Python identifier against PEP 8 conventions
73
- */
74
- function checkPythonNaming(
75
- identifier: string,
76
- type: string,
77
- file: string,
78
- line: number
79
- ): NamingIssue | null {
80
- // Get naming conventions from parser
81
- const parser = getParser('dummy.py');
82
- const conventions = parser?.getNamingConventions();
83
- if (!conventions) return null;
84
-
85
- // Skip special methods and exceptions
86
- if (conventions.exceptions?.includes(identifier)) {
87
- return null;
88
- }
89
-
90
- // Check based on type
91
- if (type === 'class') {
92
- // Classes should be PascalCase
93
- if (!conventions.classPattern.test(identifier)) {
94
- return {
95
- type: 'poor-naming',
96
- identifier,
97
- file,
98
- line,
99
- column: 0,
100
- severity: Severity.Major,
101
- category: 'naming',
102
- suggestion: `Class names should use PascalCase (e.g., ${toPascalCase(identifier)})`,
103
- };
104
- }
105
- } else if (type === 'function') {
106
- // Functions should be snake_case
107
- if (!conventions.functionPattern.test(identifier)) {
108
- // Check if it's incorrectly using camelCase
109
- if (/^[a-z][a-zA-Z0-9]*$/.test(identifier) && /[A-Z]/.test(identifier)) {
110
- return {
111
- type: 'convention-mix',
112
- identifier,
113
- file,
114
- line,
115
- column: 0,
116
- severity: Severity.Major,
117
- category: 'naming',
118
- suggestion: `Function names should use snake_case, not camelCase (e.g., ${toSnakeCase(identifier)})`,
119
- };
120
- }
121
- }
122
- } else if (type === 'const' || type === 'variable') {
123
- // Check if it looks like a constant (all uppercase)
124
- if (identifier === identifier.toUpperCase() && identifier.length > 1) {
125
- // Constants should be UPPER_CASE_WITH_UNDERSCORES
126
- if (!conventions.constantPattern.test(identifier)) {
127
- return {
128
- type: 'poor-naming',
129
- identifier,
130
- file,
131
- line,
132
- column: 0,
133
- severity: Severity.Minor,
134
- category: 'naming',
135
- suggestion: 'Constants should use UPPER_CASE_WITH_UNDERSCORES',
136
- };
137
- }
138
- } else {
139
- // Regular variables should be snake_case
140
- if (!conventions.variablePattern.test(identifier)) {
141
- // Check if it's using camelCase (common mistake from JS/TS developers)
142
- if (
143
- /^[a-z][a-zA-Z0-9]*$/.test(identifier) &&
144
- /[A-Z]/.test(identifier)
145
- ) {
146
- return {
147
- type: 'convention-mix',
148
- identifier,
149
- file,
150
- line,
151
- column: 0,
152
- severity: Severity.Major,
153
- category: 'naming',
154
- suggestion: `Variable names should use snake_case, not camelCase (e.g., ${toSnakeCase(identifier)})`,
155
- };
156
- }
157
- }
158
- }
159
- }
160
-
161
- return null;
162
- }
163
-
164
- /**
165
- * Convert camelCase to snake_case
166
- */
167
- function toSnakeCase(str: string): string {
168
- return str
169
- .replace(/([A-Z])/g, '_$1')
170
- .toLowerCase()
171
- .replace(/^_/, '');
172
- }
173
-
174
- /**
175
- * Convert snake_case to PascalCase
176
- */
177
- function toPascalCase(str: string): string {
178
- return str
179
- .split('_')
180
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
181
- .join('');
182
- }
183
-
184
- /**
185
- * Detect common Python anti-patterns in naming
186
- */
187
- export function detectPythonNamingAntiPatterns(
188
- _files: string[]
189
- ): NamingIssue[] {
190
- const issues: NamingIssue[] = [];
191
-
192
- // Parameter currently unused; reference to avoid lint warnings
193
- void _files;
194
-
195
- // Anti-pattern 1: Using camelCase in Python (common for JS/TS developers)
196
- // Anti-pattern 2: Using PascalCase for functions
197
- // Anti-pattern 3: Not using leading underscore for private methods
198
- // Anti-pattern 4: Using single letter names outside of comprehensions
199
-
200
- // These will be implemented as we refine the analyzer
201
-
202
- return issues;
203
- }