@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4
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.
- package/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +15 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,236 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
* Post-install script to set up security scanners
|
|
4
|
-
* Automatically installs required scanners for the platform
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { exec } from 'child_process';
|
|
8
|
-
import { promisify } from 'util';
|
|
9
|
-
import https from 'https';
|
|
10
|
-
import http from 'http';
|
|
11
|
-
import fs from 'fs';
|
|
12
|
-
import path from 'path';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
import { createWriteStream } from 'fs';
|
|
15
|
-
import { pipeline } from 'stream/promises';
|
|
16
|
-
|
|
17
|
-
const execAsync = promisify(exec);
|
|
18
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
-
const __dirname = path.dirname(__filename);
|
|
20
|
-
|
|
21
|
-
const SCANNER_DIR = path.join(__dirname, '..', 'node_modules', '.scanners');
|
|
22
|
-
const SEMGREP_VERSION = 'v1.55.0';
|
|
23
|
-
|
|
24
|
-
console.log('═══════════════════════════════════════════════════════════');
|
|
25
|
-
console.log(' Installing Security Scanners');
|
|
26
|
-
console.log('═══════════════════════════════════════════════════════════\n');
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Main installation function
|
|
30
|
-
*/
|
|
31
|
-
async function installScanners() {
|
|
32
|
-
// Ensure scanner directory exists
|
|
33
|
-
await fs.promises.mkdir(SCANNER_DIR, { recursive: true });
|
|
34
|
-
|
|
35
|
-
// 1. Check ESLint Security Plugin (should be in package.json)
|
|
36
|
-
await checkESLintSecurity();
|
|
37
|
-
|
|
38
|
-
// 2. Install Semgrep standalone binary
|
|
39
|
-
await installSemgrep();
|
|
40
|
-
|
|
41
|
-
// 3. Optionally install Python scanners if Python is available
|
|
42
|
-
await installPythonScanners();
|
|
43
|
-
|
|
44
|
-
console.log('\n═══════════════════════════════════════════════════════════');
|
|
45
|
-
console.log(' Installation Complete');
|
|
46
|
-
console.log('═══════════════════════════════════════════════════════════\n');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Check if ESLint Security Plugin is installed
|
|
51
|
-
*/
|
|
52
|
-
async function checkESLintSecurity() {
|
|
53
|
-
console.log('📦 Checking ESLint Security Plugin...');
|
|
54
|
-
try {
|
|
55
|
-
await import('eslint-plugin-security');
|
|
56
|
-
console.log(' ✅ eslint-plugin-security is installed\n');
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.log(' ⚠️ eslint-plugin-security not found');
|
|
59
|
-
console.log(' Run: npm install --save-dev eslint-plugin-security\n');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Install Semgrep standalone binary for the current platform
|
|
65
|
-
*/
|
|
66
|
-
async function installSemgrep() {
|
|
67
|
-
console.log('🔍 Installing Semgrep...');
|
|
68
|
-
|
|
69
|
-
const platform = process.platform;
|
|
70
|
-
const arch = process.arch;
|
|
71
|
-
|
|
72
|
-
// Check if semgrep is already installed globally
|
|
73
|
-
try {
|
|
74
|
-
const result = await execAsync('semgrep --version', { timeout: 5000 });
|
|
75
|
-
console.log(` ✅ Semgrep already installed: ${result.stdout.trim()}`);
|
|
76
|
-
console.log(' Using system-installed Semgrep\n');
|
|
77
|
-
return;
|
|
78
|
-
} catch (error) {
|
|
79
|
-
console.log(' Semgrep not found in PATH, installing standalone binary...');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Determine download URL based on platform
|
|
83
|
-
const binaryInfo = getSemgrepBinaryInfo(platform, arch);
|
|
84
|
-
|
|
85
|
-
if (!binaryInfo) {
|
|
86
|
-
console.log(` ⚠️ No Semgrep binary available for ${platform}-${arch}`);
|
|
87
|
-
console.log(' Please install manually: https://semgrep.dev/docs/getting-started/\n');
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
const binaryPath = path.join(SCANNER_DIR, 'semgrep');
|
|
93
|
-
|
|
94
|
-
console.log(` Downloading from ${binaryInfo.url}...`);
|
|
95
|
-
await downloadFile(binaryInfo.url, binaryPath);
|
|
96
|
-
|
|
97
|
-
// Make executable
|
|
98
|
-
await fs.promises.chmod(binaryPath, 0o755);
|
|
99
|
-
|
|
100
|
-
console.log(' ✅ Semgrep installed successfully');
|
|
101
|
-
console.log(` Location: ${binaryPath}\n`);
|
|
102
|
-
|
|
103
|
-
// Add to PATH environment note
|
|
104
|
-
console.log(' Note: To use system-wide, add to PATH or install globally:');
|
|
105
|
-
console.log(' pip install semgrep\n');
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.log(` ⚠️ Failed to install Semgrep: ${error.message}`);
|
|
108
|
-
console.log(' You can install manually: pip install semgrep\n');
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Get Semgrep binary info for platform
|
|
114
|
-
*/
|
|
115
|
-
function getSemgrepBinaryInfo(platform, arch) {
|
|
116
|
-
// Semgrep binary URLs (using latest stable release)
|
|
117
|
-
// Note: Semgrep doesn't provide standalone binaries anymore for all platforms
|
|
118
|
-
// They recommend using pip install or Docker
|
|
119
|
-
|
|
120
|
-
// For now, we'll provide instructions rather than downloading
|
|
121
|
-
// The actual implementation would use Semgrep's Python package
|
|
122
|
-
|
|
123
|
-
return null; // Will trigger manual installation message
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Install Python-based scanners (Bandit, pip-audit) if Python is available
|
|
128
|
-
*/
|
|
129
|
-
async function installPythonScanners() {
|
|
130
|
-
console.log('🐍 Checking Python scanners...');
|
|
131
|
-
|
|
132
|
-
// Check if Python is available
|
|
133
|
-
let pythonCommand = null;
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
await execAsync('python3 --version', { timeout: 5000 });
|
|
137
|
-
pythonCommand = 'python3';
|
|
138
|
-
} catch (error) {
|
|
139
|
-
try {
|
|
140
|
-
await execAsync('python --version', { timeout: 5000 });
|
|
141
|
-
pythonCommand = 'python';
|
|
142
|
-
} catch (error2) {
|
|
143
|
-
console.log(' ⚠️ Python not found - skipping Python scanners');
|
|
144
|
-
console.log(' To enable Python scanning, install Python and run:');
|
|
145
|
-
console.log(' pip install semgrep bandit pip-audit checkov yamllint\n');
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
console.log(` ✅ Python found: ${pythonCommand}`);
|
|
151
|
-
|
|
152
|
-
// Security scanners
|
|
153
|
-
await installViaPip('semgrep', pythonCommand);
|
|
154
|
-
await installViaPip('bandit', pythonCommand);
|
|
155
|
-
await installViaPip('pip-audit', pythonCommand);
|
|
156
|
-
|
|
157
|
-
// Config validation tools
|
|
158
|
-
await installViaPip('checkov', pythonCommand);
|
|
159
|
-
await installViaPip('yamllint', pythonCommand);
|
|
160
|
-
|
|
161
|
-
console.log('');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Install a Python package via pip
|
|
166
|
-
*/
|
|
167
|
-
async function installViaPip(packageName, pythonCommand) {
|
|
168
|
-
try {
|
|
169
|
-
// Check if already installed
|
|
170
|
-
const checkResult = await execAsync(`${pythonCommand} -m pip show ${packageName}`, {
|
|
171
|
-
timeout: 5000
|
|
172
|
-
});
|
|
173
|
-
console.log(` ✅ ${packageName} already installed`);
|
|
174
|
-
return true;
|
|
175
|
-
} catch (error) {
|
|
176
|
-
// Not installed, try to install
|
|
177
|
-
console.log(` Installing ${packageName}...`);
|
|
178
|
-
try {
|
|
179
|
-
await execAsync(`${pythonCommand} -m pip install --user ${packageName}`, {
|
|
180
|
-
timeout: 60000
|
|
181
|
-
});
|
|
182
|
-
console.log(` ✅ ${packageName} installed successfully`);
|
|
183
|
-
return true;
|
|
184
|
-
} catch (installError) {
|
|
185
|
-
console.log(` ⚠️ Failed to install ${packageName}: ${installError.message}`);
|
|
186
|
-
console.log(` You can install manually: pip install ${packageName}`);
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Download a file from URL
|
|
194
|
-
*/
|
|
195
|
-
async function downloadFile(url, outputPath) {
|
|
196
|
-
return new Promise((resolve, reject) => {
|
|
197
|
-
const client = url.startsWith('https') ? https : http;
|
|
198
|
-
|
|
199
|
-
client.get(url, (response) => {
|
|
200
|
-
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
201
|
-
// Follow redirect
|
|
202
|
-
downloadFile(response.headers.location, outputPath)
|
|
203
|
-
.then(resolve)
|
|
204
|
-
.catch(reject);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (response.statusCode !== 200) {
|
|
209
|
-
reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const fileStream = createWriteStream(outputPath);
|
|
214
|
-
response.pipe(fileStream);
|
|
215
|
-
|
|
216
|
-
fileStream.on('finish', () => {
|
|
217
|
-
fileStream.close();
|
|
218
|
-
resolve();
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
fileStream.on('error', (error) => {
|
|
222
|
-
fs.unlink(outputPath, () => {}); // Delete partial file
|
|
223
|
-
reject(error);
|
|
224
|
-
});
|
|
225
|
-
}).on('error', reject);
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Run installation
|
|
230
|
-
installScanners().catch((error) => {
|
|
231
|
-
console.error('❌ Installation failed:', error.message);
|
|
232
|
-
console.error('\nYou can manually install scanners:');
|
|
233
|
-
console.error(' npm install --save-dev eslint-plugin-security');
|
|
234
|
-
console.error(' pip install semgrep bandit pip-audit');
|
|
235
|
-
process.exit(0); // Don't fail npm install
|
|
236
|
-
});
|
|
2
|
+
const a0_0x570fe3=a0_0x5db4;(function(_0x47e640,_0x195092){const _0x37f2b9=a0_0x5db4,_0x4d1317=_0x47e640();while(!![]){try{const _0x281b76=parseInt(_0x37f2b9(0x20b))/0x1*(-parseInt(_0x37f2b9(0x217))/0x2)+parseInt(_0x37f2b9(0x225))/0x3+parseInt(_0x37f2b9(0x224))/0x4*(-parseInt(_0x37f2b9(0x1f7))/0x5)+parseInt(_0x37f2b9(0x1f3))/0x6*(-parseInt(_0x37f2b9(0x1df))/0x7)+-parseInt(_0x37f2b9(0x208))/0x8+parseInt(_0x37f2b9(0x1f4))/0x9+-parseInt(_0x37f2b9(0x20c))/0xa;if(_0x281b76===_0x195092)break;else _0x4d1317['push'](_0x4d1317['shift']());}catch(_0x34c577){_0x4d1317['push'](_0x4d1317['shift']());}}}(a0_0x34cb,0x43a6c));import{exec}from'child_process';import{promisify}from'util';import a0_0x3a3dea from'https';import a0_0x3bb35b from'http';import a0_0x4aa9b4 from'fs';import a0_0x5805e8 from'path';import{fileURLToPath}from'url';import{createWriteStream}from'fs';import{pipeline}from'stream/promises';const execAsync=promisify(exec),__filename=fileURLToPath(import.meta.url),__dirname=a0_0x5805e8[a0_0x570fe3(0x1fe)](__filename),SCANNER_DIR=a0_0x5805e8[a0_0x570fe3(0x1e3)](__dirname,'..','node_modules','.scanners'),SEMGREP_VERSION=a0_0x570fe3(0x1fc);console[a0_0x570fe3(0x223)](a0_0x570fe3(0x1f8)),console[a0_0x570fe3(0x223)](a0_0x570fe3(0x1fa)),console[a0_0x570fe3(0x223)](a0_0x570fe3(0x222));function a0_0x5db4(_0x274527,_0x1161d5){_0x274527=_0x274527-0x1df;const _0x34cb5a=a0_0x34cb();let _0x5db4b4=_0x34cb5a[_0x274527];return _0x5db4b4;}async function installScanners(){const _0x5a3b1e=a0_0x570fe3;await a0_0x4aa9b4[_0x5a3b1e(0x1f0)][_0x5a3b1e(0x207)](SCANNER_DIR,{'recursive':!![]}),await checkESLintSecurity(),await installSemgrep(),await installPythonScanners(),console['log']('\x0a═══════════════════════════════════════════════════════════'),console[_0x5a3b1e(0x223)](_0x5a3b1e(0x1e1)),console[_0x5a3b1e(0x223)](_0x5a3b1e(0x222));}async function checkESLintSecurity(){const _0x94689c=a0_0x570fe3;console[_0x94689c(0x223)](_0x94689c(0x203));try{await import(_0x94689c(0x204)),console[_0x94689c(0x223)](_0x94689c(0x1e0));}catch(_0x1a1cef){console[_0x94689c(0x223)]('\x20\x20\x20⚠️\x20\x20eslint-plugin-security\x20not\x20found'),console[_0x94689c(0x223)](_0x94689c(0x21b));}}async function installSemgrep(){const _0x40b25e=a0_0x570fe3;console[_0x40b25e(0x223)]('🔍\x20Installing\x20Semgrep...');const _0x2150ee=process[_0x40b25e(0x20d)],_0x49f217=process[_0x40b25e(0x213)];try{const _0x4d4658=await execAsync(_0x40b25e(0x206),{'timeout':0x1388});console[_0x40b25e(0x223)](_0x40b25e(0x1f5)+_0x4d4658[_0x40b25e(0x219)]['trim']()),console[_0x40b25e(0x223)]('\x20\x20\x20Using\x20system-installed\x20Semgrep\x0a');return;}catch(_0x237db6){console[_0x40b25e(0x223)](_0x40b25e(0x228));}const _0x18cf18=getSemgrepBinaryInfo(_0x2150ee,_0x49f217);if(!_0x18cf18){console[_0x40b25e(0x223)]('\x20\x20\x20⚠️\x20\x20No\x20Semgrep\x20binary\x20available\x20for\x20'+_0x2150ee+'-'+_0x49f217),console['log'](_0x40b25e(0x1f1));return;}try{const _0x1adfa6=a0_0x5805e8[_0x40b25e(0x1e3)](SCANNER_DIR,_0x40b25e(0x1ec));console[_0x40b25e(0x223)](_0x40b25e(0x20f)+_0x18cf18['url']+_0x40b25e(0x1ee)),await downloadFile(_0x18cf18['url'],_0x1adfa6),await a0_0x4aa9b4[_0x40b25e(0x1f0)][_0x40b25e(0x209)](_0x1adfa6,0x1ed),console[_0x40b25e(0x223)](_0x40b25e(0x200)),console['log'](_0x40b25e(0x1e7)+_0x1adfa6+'\x0a'),console['log'](_0x40b25e(0x1ea)),console['log'](_0x40b25e(0x215));}catch(_0x5e3cd2){console[_0x40b25e(0x223)](_0x40b25e(0x1fb)+_0x5e3cd2[_0x40b25e(0x214)]),console[_0x40b25e(0x223)](_0x40b25e(0x205));}}function a0_0x34cb(){const _0x40c04f=['yamllint','catch','\x20-m\x20pip\x20show\x20','\x20\x20\x20You\x20can\x20install\x20manually:\x20pip\x20install\x20','═══════════════════════════════════════════════════════════\x0a','log','17356ZWLSDg','1385766PRgart','\x20\x20npm\x20install\x20--save-dev\x20eslint-plugin-security','close','\x20\x20\x20Semgrep\x20not\x20found\x20in\x20PATH,\x20installing\x20standalone\x20binary...','7xTQKwa','\x20\x20\x20✅\x20eslint-plugin-security\x20is\x20installed\x0a','\x20\x20Installation\x20Complete','\x20\x20pip\x20install\x20semgrep\x20bandit\x20pip-audit','join','❌\x20Installation\x20failed:','startsWith','Failed\x20to\x20download:\x20HTTP\x20','\x20\x20\x20Location:\x20','python3','\x20\x20\x20pip\x20install\x20semgrep\x20bandit\x20pip-audit\x20checkov\x20yamllint\x0a','\x20\x20\x20Note:\x20To\x20use\x20system-wide,\x20add\x20to\x20PATH\x20or\x20install\x20globally:','bandit','semgrep','\x0aYou\x20can\x20manually\x20install\x20scanners:','...','unlink','promises','\x20\x20\x20Please\x20install\x20manually:\x20https://semgrep.dev/docs/getting-started/\x0a','\x20-m\x20pip\x20install\x20--user\x20','282432lXXpJO','2955357ixrIxp','\x20\x20\x20✅\x20Semgrep\x20already\x20installed:\x20','error','220seyjHO','═══════════════════════════════════════════════════════════','finish','\x20\x20Installing\x20Security\x20Scanners','\x20\x20\x20⚠️\x20\x20Failed\x20to\x20install\x20Semgrep:\x20','v1.55.0','\x20\x20\x20To\x20enable\x20Python\x20scanning,\x20install\x20Python\x20and\x20run:','dirname','\x20\x20\x20Installing\x20','\x20\x20\x20✅\x20Semgrep\x20installed\x20successfully','get','\x20\x20\x20✅\x20','📦\x20Checking\x20ESLint\x20Security\x20Plugin...','eslint-plugin-security','\x20\x20\x20You\x20can\x20install\x20manually:\x20pip\x20install\x20semgrep\x0a','semgrep\x20--version','mkdir','1536496zuMzUQ','chmod','\x20installed\x20successfully','4682dUowCD','456890vgOdGw','platform','checkov','\x20\x20\x20Downloading\x20from\x20','🐍\x20Checking\x20Python\x20scanners...','\x20\x20\x20⚠️\x20\x20Failed\x20to\x20install\x20','pipe','arch','message','\x20\x20\x20pip\x20install\x20semgrep\x0a','then','16cvvpiO','exit','stdout','statusCode','\x20\x20\x20Run:\x20npm\x20install\x20--save-dev\x20eslint-plugin-security\x0a','https','location'];a0_0x34cb=function(){return _0x40c04f;};return a0_0x34cb();}function getSemgrepBinaryInfo(_0x5890fa,_0x115797){return null;}async function installPythonScanners(){const _0x25b35c=a0_0x570fe3;console[_0x25b35c(0x223)](_0x25b35c(0x210));let _0x215e37=null;try{await execAsync('python3\x20--version',{'timeout':0x1388}),_0x215e37=_0x25b35c(0x1e8);}catch(_0x5acdee){try{await execAsync('python\x20--version',{'timeout':0x1388}),_0x215e37='python';}catch(_0x14f825){console[_0x25b35c(0x223)]('\x20\x20\x20⚠️\x20\x20Python\x20not\x20found\x20-\x20skipping\x20Python\x20scanners'),console[_0x25b35c(0x223)](_0x25b35c(0x1fd)),console[_0x25b35c(0x223)](_0x25b35c(0x1e9));return;}}console[_0x25b35c(0x223)]('\x20\x20\x20✅\x20Python\x20found:\x20'+_0x215e37),await installViaPip(_0x25b35c(0x1ec),_0x215e37),await installViaPip(_0x25b35c(0x1eb),_0x215e37),await installViaPip('pip-audit',_0x215e37),await installViaPip(_0x25b35c(0x20e),_0x215e37),await installViaPip(_0x25b35c(0x21e),_0x215e37),console['log']('');}async function installViaPip(_0x42fb33,_0x3c85c1){const _0x295783=a0_0x570fe3;try{const _0xf43ca4=await execAsync(_0x3c85c1+_0x295783(0x220)+_0x42fb33,{'timeout':0x1388});return console['log'](_0x295783(0x202)+_0x42fb33+'\x20already\x20installed'),!![];}catch(_0x219b65){console['log'](_0x295783(0x1ff)+_0x42fb33+_0x295783(0x1ee));try{return await execAsync(_0x3c85c1+_0x295783(0x1f2)+_0x42fb33,{'timeout':0xea60}),console[_0x295783(0x223)](_0x295783(0x202)+_0x42fb33+_0x295783(0x20a)),!![];}catch(_0x50fced){return console[_0x295783(0x223)](_0x295783(0x211)+_0x42fb33+':\x20'+_0x50fced[_0x295783(0x214)]),console[_0x295783(0x223)](_0x295783(0x221)+_0x42fb33),![];}}}async function downloadFile(_0x408a77,_0x2e4133){return new Promise((_0x780847,_0x5a579d)=>{const _0xc9979a=a0_0x5db4,_0xc55ac8=_0x408a77[_0xc9979a(0x1e5)](_0xc9979a(0x21c))?a0_0x3a3dea:a0_0x3bb35b;_0xc55ac8[_0xc9979a(0x201)](_0x408a77,_0x125c43=>{const _0x2781b8=_0xc9979a;if(_0x125c43[_0x2781b8(0x21a)]===0x12e||_0x125c43[_0x2781b8(0x21a)]===0x12d){downloadFile(_0x125c43['headers'][_0x2781b8(0x21d)],_0x2e4133)[_0x2781b8(0x216)](_0x780847)[_0x2781b8(0x21f)](_0x5a579d);return;}if(_0x125c43['statusCode']!==0xc8){_0x5a579d(new Error(_0x2781b8(0x1e6)+_0x125c43[_0x2781b8(0x21a)]));return;}const _0x141344=createWriteStream(_0x2e4133);_0x125c43[_0x2781b8(0x212)](_0x141344),_0x141344['on'](_0x2781b8(0x1f9),()=>{const _0x544536=_0x2781b8;_0x141344[_0x544536(0x227)](),_0x780847();}),_0x141344['on']('error',_0x41121f=>{const _0x523975=_0x2781b8;a0_0x4aa9b4[_0x523975(0x1ef)](_0x2e4133,()=>{}),_0x5a579d(_0x41121f);});})['on'](_0xc9979a(0x1f6),_0x5a579d);});}installScanners()[a0_0x570fe3(0x21f)](_0x4711c1=>{const _0x2f649d=a0_0x570fe3;console[_0x2f649d(0x1f6)](_0x2f649d(0x1e4),_0x4711c1[_0x2f649d(0x214)]),console[_0x2f649d(0x1f6)](_0x2f649d(0x1ed)),console[_0x2f649d(0x1f6)](_0x2f649d(0x226)),console[_0x2f649d(0x1f6)](_0x2f649d(0x1e2)),process[_0x2f649d(0x218)](0x0);});
|
|
@@ -1,297 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* CSSAnalyzer - CSS/SCSS/LESS code analysis using PostCSS and Stylelint
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* - Analyze CSS, SCSS, and LESS files for syntax errors
|
|
6
|
-
* - Validate style rules and properties
|
|
7
|
-
* - Detect common CSS issues and bad practices
|
|
8
|
-
* - Support preprocessor syntaxes (SCSS, LESS)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { STATIC_ANALYSIS } from '../utilities/constants.js';
|
|
12
|
-
|
|
13
|
-
class CSSAnalyzer {
|
|
14
|
-
constructor(logger = null) {
|
|
15
|
-
this.logger = logger;
|
|
16
|
-
this.stylelint = null;
|
|
17
|
-
this.postcss = null;
|
|
18
|
-
this.postcssScss = null;
|
|
19
|
-
this.postcssLess = null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Analyze CSS/SCSS/LESS code
|
|
24
|
-
* @param {string} filePath - Path to file
|
|
25
|
-
* @param {string} content - File content
|
|
26
|
-
* @param {Object} options - Analysis options
|
|
27
|
-
* @returns {Promise<Array>} Array of diagnostics
|
|
28
|
-
*/
|
|
29
|
-
async analyze(filePath, content, options = {}) {
|
|
30
|
-
try {
|
|
31
|
-
const diagnostics = [];
|
|
32
|
-
const language = this.detectLanguage(filePath);
|
|
33
|
-
|
|
34
|
-
// Check syntax using PostCSS
|
|
35
|
-
const syntaxErrors = await this.checkSyntax(filePath, content, language);
|
|
36
|
-
diagnostics.push(...syntaxErrors);
|
|
37
|
-
|
|
38
|
-
// Only run style linting if no syntax errors
|
|
39
|
-
if (syntaxErrors.length === 0) {
|
|
40
|
-
const styleIssues = await this.lintStyles(filePath, content, language);
|
|
41
|
-
diagnostics.push(...styleIssues);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.logger?.debug('CSS analysis completed', {
|
|
45
|
-
file: filePath,
|
|
46
|
-
language,
|
|
47
|
-
totalDiagnostics: diagnostics.length,
|
|
48
|
-
errors: diagnostics.filter(d => d.severity === STATIC_ANALYSIS.SEVERITY.ERROR).length,
|
|
49
|
-
warnings: diagnostics.filter(d => d.severity === STATIC_ANALYSIS.SEVERITY.WARNING).length
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return diagnostics;
|
|
53
|
-
|
|
54
|
-
} catch (error) {
|
|
55
|
-
this.logger?.error('CSS analysis failed', {
|
|
56
|
-
file: filePath,
|
|
57
|
-
error: error.message
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Return empty array on error to allow other analysis to continue
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Check CSS syntax using PostCSS
|
|
67
|
-
* @private
|
|
68
|
-
*/
|
|
69
|
-
async checkSyntax(filePath, content, language) {
|
|
70
|
-
const diagnostics = [];
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
// Lazy load PostCSS and syntax parsers
|
|
74
|
-
if (!this.postcss) {
|
|
75
|
-
const postcssModule = await import('postcss');
|
|
76
|
-
this.postcss = postcssModule.default;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let syntax = null;
|
|
80
|
-
|
|
81
|
-
if (language === 'scss') {
|
|
82
|
-
if (!this.postcssScss) {
|
|
83
|
-
const scssModule = await import('postcss-scss');
|
|
84
|
-
this.postcssScss = scssModule.default;
|
|
85
|
-
}
|
|
86
|
-
syntax = this.postcssScss;
|
|
87
|
-
} else if (language === 'less') {
|
|
88
|
-
if (!this.postcssLess) {
|
|
89
|
-
const lessModule = await import('postcss-less');
|
|
90
|
-
this.postcssLess = lessModule.default;
|
|
91
|
-
}
|
|
92
|
-
syntax = this.postcssLess;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Parse CSS with PostCSS
|
|
96
|
-
const result = this.postcss().process(content, {
|
|
97
|
-
from: filePath,
|
|
98
|
-
syntax
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// PostCSS parsing is synchronous - accessing result.root will throw if syntax error
|
|
102
|
-
const root = result.root;
|
|
103
|
-
|
|
104
|
-
// If we get here, syntax is valid
|
|
105
|
-
this.logger?.debug('PostCSS syntax check passed', { file: filePath });
|
|
106
|
-
|
|
107
|
-
} catch (error) {
|
|
108
|
-
// PostCSS syntax error
|
|
109
|
-
const diagnostic = this.formatPostCSSError(error, filePath);
|
|
110
|
-
if (diagnostic) {
|
|
111
|
-
diagnostics.push(diagnostic);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return diagnostics;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Lint styles using Stylelint
|
|
120
|
-
* @private
|
|
121
|
-
*/
|
|
122
|
-
async lintStyles(filePath, content, language) {
|
|
123
|
-
const diagnostics = [];
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
// Lazy load Stylelint
|
|
127
|
-
if (!this.stylelint) {
|
|
128
|
-
const stylelintModule = await import('stylelint');
|
|
129
|
-
this.stylelint = stylelintModule.default;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Configure Stylelint
|
|
133
|
-
const config = {
|
|
134
|
-
extends: ['stylelint-config-standard'],
|
|
135
|
-
rules: {
|
|
136
|
-
// Custom rules for better analysis
|
|
137
|
-
'color-no-invalid-hex': true,
|
|
138
|
-
'font-family-no-duplicate-names': true,
|
|
139
|
-
'function-calc-no-invalid': true,
|
|
140
|
-
'string-no-newline': true,
|
|
141
|
-
'unit-no-unknown': true,
|
|
142
|
-
'property-no-unknown': true,
|
|
143
|
-
'declaration-block-no-duplicate-properties': true,
|
|
144
|
-
'selector-pseudo-class-no-unknown': true,
|
|
145
|
-
'selector-pseudo-element-no-unknown': true,
|
|
146
|
-
'selector-type-no-unknown': [true, {
|
|
147
|
-
ignoreTypes: ['/^custom-/', 'ng-deep'] // Allow custom elements
|
|
148
|
-
}],
|
|
149
|
-
'media-feature-name-no-unknown': true,
|
|
150
|
-
'at-rule-no-unknown': language === 'scss' ? [true, {
|
|
151
|
-
ignoreAtRules: ['mixin', 'include', 'extend', 'if', 'else', 'for', 'each', 'while', 'function', 'return', 'content', 'use', 'forward']
|
|
152
|
-
}] : language === 'less' ? [true, {
|
|
153
|
-
ignoreAtRules: ['plugin']
|
|
154
|
-
}] : true,
|
|
155
|
-
'comment-no-empty': true,
|
|
156
|
-
'no-duplicate-selectors': true,
|
|
157
|
-
'no-empty-source': null, // Allow empty files
|
|
158
|
-
'block-no-empty': true,
|
|
159
|
-
'declaration-block-no-shorthand-property-overrides': true,
|
|
160
|
-
'font-family-no-missing-generic-family-keyword': true,
|
|
161
|
-
'function-linear-gradient-no-nonstandard-direction': true,
|
|
162
|
-
'no-descending-specificity': null, // Too strict for real projects
|
|
163
|
-
'no-duplicate-at-import-rules': true,
|
|
164
|
-
'no-extra-semicolons': true,
|
|
165
|
-
'no-invalid-double-slash-comments': true,
|
|
166
|
-
'selector-pseudo-element-colon-notation': 'double',
|
|
167
|
-
'selector-type-case': 'lower'
|
|
168
|
-
},
|
|
169
|
-
customSyntax: language === 'scss' ? 'postcss-scss' :
|
|
170
|
-
language === 'less' ? 'postcss-less' : undefined
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// Run Stylelint
|
|
174
|
-
const result = await this.stylelint.lint({
|
|
175
|
-
code: content,
|
|
176
|
-
codeFilename: filePath,
|
|
177
|
-
config
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Process results
|
|
181
|
-
if (result.results && result.results.length > 0) {
|
|
182
|
-
const fileResult = result.results[0];
|
|
183
|
-
|
|
184
|
-
if (fileResult.warnings) {
|
|
185
|
-
for (const warning of fileResult.warnings) {
|
|
186
|
-
diagnostics.push({
|
|
187
|
-
file: filePath,
|
|
188
|
-
line: warning.line || 1,
|
|
189
|
-
column: warning.column || 1,
|
|
190
|
-
severity: warning.severity === 'error'
|
|
191
|
-
? STATIC_ANALYSIS.SEVERITY.ERROR
|
|
192
|
-
: STATIC_ANALYSIS.SEVERITY.WARNING,
|
|
193
|
-
rule: warning.rule || 'unknown',
|
|
194
|
-
message: warning.text,
|
|
195
|
-
category: this.categorizeStylelintRule(warning.rule),
|
|
196
|
-
fixable: false,
|
|
197
|
-
source: 'stylelint'
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
} catch (error) {
|
|
204
|
-
this.logger?.warn('Stylelint analysis failed', {
|
|
205
|
-
file: filePath,
|
|
206
|
-
error: error.message
|
|
207
|
-
});
|
|
208
|
-
// Don't fail the whole analysis if linting fails
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return diagnostics;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Format PostCSS error into diagnostic
|
|
216
|
-
* @private
|
|
217
|
-
*/
|
|
218
|
-
formatPostCSSError(error, filePath) {
|
|
219
|
-
return {
|
|
220
|
-
file: filePath,
|
|
221
|
-
line: error.line || 1,
|
|
222
|
-
column: error.column || 1,
|
|
223
|
-
severity: STATIC_ANALYSIS.SEVERITY.ERROR,
|
|
224
|
-
rule: error.name || 'CssSyntaxError',
|
|
225
|
-
message: error.reason || error.message,
|
|
226
|
-
category: STATIC_ANALYSIS.CATEGORY.SYNTAX,
|
|
227
|
-
fixable: false,
|
|
228
|
-
source: 'postcss',
|
|
229
|
-
code: error.source || undefined
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Categorize Stylelint rule into analysis category
|
|
235
|
-
* @private
|
|
236
|
-
*/
|
|
237
|
-
categorizeStylelintRule(rule) {
|
|
238
|
-
if (!rule) return STATIC_ANALYSIS.CATEGORY.STYLE;
|
|
239
|
-
|
|
240
|
-
const ruleLower = rule.toLowerCase();
|
|
241
|
-
|
|
242
|
-
if (ruleLower.includes('no-invalid') ||
|
|
243
|
-
ruleLower.includes('no-unknown') ||
|
|
244
|
-
ruleLower.includes('no-empty') ||
|
|
245
|
-
ruleLower.includes('syntax')) {
|
|
246
|
-
return STATIC_ANALYSIS.CATEGORY.SYNTAX;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (ruleLower.includes('performance') ||
|
|
250
|
-
ruleLower.includes('optimize')) {
|
|
251
|
-
return STATIC_ANALYSIS.CATEGORY.PERFORMANCE;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (ruleLower.includes('best-practice') ||
|
|
255
|
-
ruleLower.includes('recommended')) {
|
|
256
|
-
return STATIC_ANALYSIS.CATEGORY.BEST_PRACTICE;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return STATIC_ANALYSIS.CATEGORY.STYLE;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Detect language from file path
|
|
264
|
-
* @private
|
|
265
|
-
*/
|
|
266
|
-
detectLanguage(filePath) {
|
|
267
|
-
const ext = filePath.toLowerCase();
|
|
268
|
-
|
|
269
|
-
if (ext.endsWith('.scss') || ext.endsWith('.sass')) {
|
|
270
|
-
return 'scss';
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (ext.endsWith('.less')) {
|
|
274
|
-
return 'less';
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return 'css';
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Get supported file extensions
|
|
282
|
-
* @returns {Array<string>} Array of supported extensions
|
|
283
|
-
*/
|
|
284
|
-
getSupportedExtensions() {
|
|
285
|
-
return ['.css', '.scss', '.sass', '.less'];
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Check if auto-fix is supported
|
|
290
|
-
* @returns {boolean} True if auto-fix is supported
|
|
291
|
-
*/
|
|
292
|
-
supportsAutoFix() {
|
|
293
|
-
return false; // Auto-fix not implemented yet
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export default CSSAnalyzer;
|
|
1
|
+
const a0_0x3c1b62=a0_0x2137;(function(_0x182bac,_0x50c3ac){const _0x5a187c=a0_0x2137,_0x125a3e=_0x182bac();while(!![]){try{const _0x208023=parseInt(_0x5a187c(0x1df))/0x1+parseInt(_0x5a187c(0x1de))/0x2+-parseInt(_0x5a187c(0x1c8))/0x3*(-parseInt(_0x5a187c(0x1f7))/0x4)+parseInt(_0x5a187c(0x1f9))/0x5*(parseInt(_0x5a187c(0x1f5))/0x6)+parseInt(_0x5a187c(0x1ef))/0x7*(parseInt(_0x5a187c(0x1e4))/0x8)+-parseInt(_0x5a187c(0x1e8))/0x9+-parseInt(_0x5a187c(0x1f2))/0xa*(parseInt(_0x5a187c(0x1cf))/0xb);if(_0x208023===_0x50c3ac)break;else _0x125a3e['push'](_0x125a3e['shift']());}catch(_0x77e2d8){_0x125a3e['push'](_0x125a3e['shift']());}}}(a0_0x3f8b,0x436a7));function a0_0x3f8b(){const _0x143450=['u0vwrvjjvfK','zM9YBwf0ug9ZDentu0vYCM9Y','u1rzteu','yw5HBhL6zq','CNvSzq','BM8TAw52ywXPza','Bg9Nz2vY','B3b0Aw1PEMu','CMvHC29U','D2fYBMLUz3m','Cg9ZDgnZC1nJC3m','C2nZCW','Dg9mB3DLCKnHC2u','lNnHC3m','mZu0otaZru1XAgvt','Aw5JBhvKzxm','y29SDw1U','C3r5BgvSAw50','BgLUzq','CM9VDa','BgLUDfn0EwXLCW','nZu4ndKYovrQDLLyyq','q0furuDpuLK','lNnJC3m','zw5KC1DPDgG','BwvZC2fNzq','ChjVy2vZCW','qKvtvf9quKfdveLdrq','BM8TDw5RBM93BG','y2f0zwDVCML6zvn0EwXLBgLUDfj1Bgu','rvjst1i','CMvZDwX0CW','C3r5BgvSAw50lwnVBMzPzY1ZDgfUzgfYza','ug9ZDentuYbZEw50yxGGy2HLy2SGCgfZC2vK','Bg93zxi','zwXZzq','mZm3nJqYCwzfC29p','mJCZoty0vMHYBNDY','zxH0zw5K','BgvUz3rO','y29UDgvUDa','C3vWCg9YDhnbDxrVrML4','mta5mZuYtNj3DKPQ','u1Lovefy','lMnZCW','uevsrK9stufoq0u','mZq4ndy4m3DZvK9dvG','zwfJAa','BgvZCW','C291CMnL','Cg9ZDgnZC0XLC3m','Cg9ZDgnZCY1SzxnZ','zgvMyxvSDa','mJe3tvHzturQ','Cg9ZDgnZCW','zgvIDwC','mtbPzxzwqu8','zg91yMXL','q3nZu3LUDgf4rxjYB3i','otK4otrXA05Iwgq','BgLUDa','ofjyr3fzDG','y2HLy2TtEw50yxG','nZvpBgfKr2G','ChvZAa','Dgv4Da','BM8Tzw1WDhK','v0fstKLorW','C3LUDgf4','zgv0zwn0tgfUz3vHz2u'];a0_0x3f8b=function(){return _0x143450;};return a0_0x3f8b();}import{STATIC_ANALYSIS}from'../utilities/constants.js';class CSSAnalyzer{constructor(_0x1e8679=null){const _0x820b16=a0_0x2137;this['logger']=_0x1e8679,this[_0x820b16(0x1cb)]=null,this['postcss']=null,this['postcssScss']=null,this[_0x820b16(0x1ec)]=null;}async[a0_0x3c1b62(0x1bd)](_0x584447,_0x26ae36,_0x36eee6={}){const _0x517cb1=a0_0x3c1b62;try{const _0x57a8a8=[],_0x7719b6=this['detectLanguage'](_0x584447),_0x597546=await this[_0x517cb1(0x1f8)](_0x584447,_0x26ae36,_0x7719b6);_0x57a8a8[_0x517cb1(0x1fa)](..._0x597546);if(_0x597546[_0x517cb1(0x1e1)]===0x0){const _0x36880d=await this[_0x517cb1(0x1ce)](_0x584447,_0x26ae36,_0x7719b6);_0x57a8a8['push'](..._0x36880d);}return this[_0x517cb1(0x1c0)]?.['debug']('CSS\x20analysis\x20completed',{'file':_0x584447,'language':_0x7719b6,'totalDiagnostics':_0x57a8a8['length'],'errors':_0x57a8a8['filter'](_0x40927a=>_0x40927a['severity']===STATIC_ANALYSIS[_0x517cb1(0x1ba)][_0x517cb1(0x1d8)])['length'],'warnings':_0x57a8a8['filter'](_0x366c99=>_0x366c99['severity']===STATIC_ANALYSIS[_0x517cb1(0x1ba)][_0x517cb1(0x1fd)])['length']}),_0x57a8a8;}catch(_0x135b9f){return this['logger']?.['error']('CSS\x20analysis\x20failed',{'file':_0x584447,'error':_0x135b9f[_0x517cb1(0x1d3)]}),[];}}async['checkSyntax'](_0x1fc2fb,_0x3fc4db,_0x2b8381){const _0x376f5f=a0_0x3c1b62,_0x514d2a=[];try{if(!this[_0x376f5f(0x1f0)]){const _0xf4ff1a=await import('postcss');this[_0x376f5f(0x1f0)]=_0xf4ff1a[_0x376f5f(0x1ee)];}let _0x43add2=null;if(_0x2b8381==='scss'){if(!this['postcssScss']){const _0x419505=await import('postcss-scss');this[_0x376f5f(0x1c4)]=_0x419505[_0x376f5f(0x1ee)];}_0x43add2=this[_0x376f5f(0x1c4)];}else{if(_0x2b8381===_0x376f5f(0x1ea)){if(!this['postcssLess']){const _0x1238ce=await import('postcss-less');this[_0x376f5f(0x1ec)]=_0x1238ce[_0x376f5f(0x1ee)];}_0x43add2=this['postcssLess'];}}const _0x1ea37b=this['postcss']()[_0x376f5f(0x1d4)](_0x3fc4db,{'from':_0x1fc2fb,'syntax':_0x43add2}),_0x480dc5=_0x1ea37b[_0x376f5f(0x1cd)];this[_0x376f5f(0x1c0)]?.[_0x376f5f(0x1f1)](_0x376f5f(0x1db),{'file':_0x1fc2fb});}catch(_0x367460){const _0x450923=this[_0x376f5f(0x1bb)](_0x367460,_0x1fc2fb);_0x450923&&_0x514d2a[_0x376f5f(0x1fa)](_0x450923);}return _0x514d2a;}async['lintStyles'](_0x4785d9,_0x48314a,_0x386709){const _0x1c14c9=a0_0x3c1b62,_0xd9e7d4=[];try{if(!this['stylelint']){const _0xff9dfb=await import('stylelint');this[_0x1c14c9(0x1cb)]=_0xff9dfb['default'];}const _0xe599a3={'extends':[_0x1c14c9(0x1da)],'rules':{'color-no-invalid-hex':!![],'font-family-no-duplicate-names':!![],'function-calc-no-invalid':!![],'string-no-newline':!![],'unit-no-unknown':!![],'property-no-unknown':!![],'declaration-block-no-duplicate-properties':!![],'selector-pseudo-class-no-unknown':!![],'selector-pseudo-element-no-unknown':!![],'selector-type-no-unknown':[!![],{'ignoreTypes':['/^custom-/','ng-deep']}],'media-feature-name-no-unknown':!![],'at-rule-no-unknown':_0x386709===_0x1c14c9(0x1c5)?[!![],{'ignoreAtRules':['mixin','include',_0x1c14c9(0x1e0),'if',_0x1c14c9(0x1dd),'for',_0x1c14c9(0x1e9),'while','function','return',_0x1c14c9(0x1e2),'use','forward']}]:_0x386709===_0x1c14c9(0x1ea)?[!![],{'ignoreAtRules':['plugin']}]:!![],'comment-no-empty':!![],'no-duplicate-selectors':!![],'no-empty-source':null,'block-no-empty':!![],'declaration-block-no-shorthand-property-overrides':!![],'font-family-no-missing-generic-family-keyword':!![],'function-linear-gradient-no-nonstandard-direction':!![],'no-descending-specificity':null,'no-duplicate-at-import-rules':!![],'no-extra-semicolons':!![],'no-invalid-double-slash-comments':!![],'selector-pseudo-element-colon-notation':_0x1c14c9(0x1f3),'selector-type-case':_0x1c14c9(0x1dc)},'customSyntax':_0x386709==='scss'?'postcss-scss':_0x386709==='less'?_0x1c14c9(0x1ed):undefined},_0x167417=await this[_0x1c14c9(0x1cb)][_0x1c14c9(0x1f6)]({'code':_0x48314a,'codeFilename':_0x4785d9,'config':_0xe599a3});if(_0x167417[_0x1c14c9(0x1d9)]&&_0x167417[_0x1c14c9(0x1d9)][_0x1c14c9(0x1e1)]>0x0){const _0x65de78=_0x167417[_0x1c14c9(0x1d9)][0x0];if(_0x65de78[_0x1c14c9(0x1c3)])for(const _0x3bb61f of _0x65de78['warnings']){_0xd9e7d4[_0x1c14c9(0x1fa)]({'file':_0x4785d9,'line':_0x3bb61f[_0x1c14c9(0x1cc)]||0x1,'column':_0x3bb61f['column']||0x1,'severity':_0x3bb61f['severity']==='error'?STATIC_ANALYSIS[_0x1c14c9(0x1ba)]['ERROR']:STATIC_ANALYSIS['SEVERITY'][_0x1c14c9(0x1fd)],'rule':_0x3bb61f[_0x1c14c9(0x1be)]||'unknown','message':_0x3bb61f[_0x1c14c9(0x1fb)],'category':this[_0x1c14c9(0x1d7)](_0x3bb61f[_0x1c14c9(0x1be)]),'fixable':![],'source':'stylelint'});}}}catch(_0x1c0582){this['logger']?.['warn']('Stylelint\x20analysis\x20failed',{'file':_0x4785d9,'error':_0x1c0582['message']});}return _0xd9e7d4;}['formatPostCSSError'](_0x136ac6,_0x378624){const _0x200c1c=a0_0x3c1b62;return{'file':_0x378624,'line':_0x136ac6[_0x200c1c(0x1cc)]||0x1,'column':_0x136ac6[_0x200c1c(0x1ca)]||0x1,'severity':STATIC_ANALYSIS['SEVERITY']['ERROR'],'rule':_0x136ac6['name']||_0x200c1c(0x1f4),'message':_0x136ac6[_0x200c1c(0x1c2)]||_0x136ac6['message'],'category':STATIC_ANALYSIS['CATEGORY'][_0x200c1c(0x1e5)],'fixable':![],'source':_0x200c1c(0x1f0),'code':_0x136ac6[_0x200c1c(0x1eb)]||undefined};}[a0_0x3c1b62(0x1d7)](_0x55a969){const _0x5eaf48=a0_0x3c1b62;if(!_0x55a969)return STATIC_ANALYSIS['CATEGORY']['STYLE'];const _0x4de4bc=_0x55a969['toLowerCase']();if(_0x4de4bc['includes'](_0x5eaf48(0x1bf))||_0x4de4bc[_0x5eaf48(0x1c9)](_0x5eaf48(0x1d6))||_0x4de4bc['includes'](_0x5eaf48(0x1fc))||_0x4de4bc[_0x5eaf48(0x1c9)](_0x5eaf48(0x1fe)))return STATIC_ANALYSIS[_0x5eaf48(0x1d0)][_0x5eaf48(0x1e5)];if(_0x4de4bc['includes']('performance')||_0x4de4bc['includes'](_0x5eaf48(0x1c1)))return STATIC_ANALYSIS[_0x5eaf48(0x1d0)][_0x5eaf48(0x1e7)];if(_0x4de4bc['includes']('best-practice')||_0x4de4bc[_0x5eaf48(0x1c9)]('recommended'))return STATIC_ANALYSIS['CATEGORY'][_0x5eaf48(0x1d5)];return STATIC_ANALYSIS['CATEGORY'][_0x5eaf48(0x1bc)];}[a0_0x3c1b62(0x1ff)](_0x43167d){const _0x44072f=a0_0x3c1b62,_0x2fc7c3=_0x43167d[_0x44072f(0x1c6)]();if(_0x2fc7c3[_0x44072f(0x1d2)](_0x44072f(0x1d1))||_0x2fc7c3[_0x44072f(0x1d2)]('.sass'))return _0x44072f(0x1c5);if(_0x2fc7c3[_0x44072f(0x1d2)]('.less'))return'less';return'css';}['getSupportedExtensions'](){const _0x4f4279=a0_0x3c1b62;return[_0x4f4279(0x1e6),'.scss',_0x4f4279(0x1c7),'.less'];}[a0_0x3c1b62(0x1e3)](){return![];}}function a0_0x2137(_0x292efe,_0x7b7589){_0x292efe=_0x292efe-0x1ba;const _0x3f8bb6=a0_0x3f8b();let _0x21374d=_0x3f8bb6[_0x292efe];if(a0_0x2137['nTvEVs']===undefined){var _0x3c1455=function(_0x2aa1d4){const _0x4cf79b='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x1e8679='',_0x584447='';for(let _0x26ae36=0x0,_0x36eee6,_0x57a8a8,_0x7719b6=0x0;_0x57a8a8=_0x2aa1d4['charAt'](_0x7719b6++);~_0x57a8a8&&(_0x36eee6=_0x26ae36%0x4?_0x36eee6*0x40+_0x57a8a8:_0x57a8a8,_0x26ae36++%0x4)?_0x1e8679+=String['fromCharCode'](0xff&_0x36eee6>>(-0x2*_0x26ae36&0x6)):0x0){_0x57a8a8=_0x4cf79b['indexOf'](_0x57a8a8);}for(let _0x597546=0x0,_0x36880d=_0x1e8679['length'];_0x597546<_0x36880d;_0x597546++){_0x584447+='%'+('00'+_0x1e8679['charCodeAt'](_0x597546)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x584447);};a0_0x2137['CgeVBw']=_0x3c1455,a0_0x2137['kWgVYh']={},a0_0x2137['nTvEVs']=!![];}const _0x4caa06=_0x3f8bb6[0x0],_0x166c18=_0x292efe+_0x4caa06,_0x1b7423=a0_0x2137['kWgVYh'][_0x166c18];return!_0x1b7423?(_0x21374d=a0_0x2137['CgeVBw'](_0x21374d),a0_0x2137['kWgVYh'][_0x166c18]=_0x21374d):_0x21374d=_0x1b7423,_0x21374d;}export default CSSAnalyzer;
|