Skip to content

Commit 09e942b

Browse files
added disabling checks
1 parent 68d5aee commit 09e942b

File tree

6 files changed

+259
-207
lines changed

6 files changed

+259
-207
lines changed

vscode-ext/package.json

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "next-css-lint",
33
"displayName": "Next.Js CSS linter",
44
"description": "Display unused CSS classes in Next.Js projects and search for class definitions",
5-
"version": "1.7.5",
5+
"version": "1.7.6",
66
"license": "MIT",
77
"repository": "https://github.com/Andcool-Systems/css-linter",
88
"author": {
@@ -14,6 +14,31 @@
1414
"engines": {
1515
"vscode": "^1.92.0"
1616
},
17+
"contributes": {
18+
"commands": [
19+
{
20+
"command": "next-css-lint.enable",
21+
"title": "Next.Js CSS linter: Enable"
22+
},
23+
{
24+
"command": "next-css-lint.disable",
25+
"title": "Next.Js CSS linter: Disable"
26+
}
27+
],
28+
"configuration": [
29+
{
30+
"title": "Next.Js CSS linter configuration",
31+
"type": "object",
32+
"properties": {
33+
"next-css-lint.enabled": {
34+
"type": "boolean",
35+
"default": true,
36+
"description": "Enable Next.Js CSS linter in current workplace"
37+
}
38+
}
39+
}
40+
]
41+
},
1742
"categories": [
1843
"Linters"
1944
],
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { existsSync, readFileSync } from 'fs';
2+
import { join, resolve } from 'path';
3+
import * as vscode from 'vscode';
4+
5+
export class CssModuleDefinitionProvider implements vscode.DefinitionProvider {
6+
async provideDefinition(
7+
document: vscode.TextDocument,
8+
position: vscode.Position,
9+
token: vscode.CancellationToken
10+
): Promise<vscode.Definition | null> {
11+
const wordRange = document.getWordRangeAtPosition(position);
12+
if (!wordRange) return null;
13+
14+
const word = document.getText(wordRange);
15+
const text = document.getText();
16+
const lineText = document.lineAt(position.line).text;
17+
18+
const regex = /(\w+)\.(\w+)/g;
19+
let match;
20+
const matches: { objectName: string; propertyName: string }[] = [];
21+
22+
while ((match = regex.exec(lineText)) !== null) {
23+
matches.push({ objectName: match[1], propertyName: match[2] });
24+
}
25+
26+
const matchData = matches.find(m => m.propertyName === word);
27+
if (!matchData) return null;
28+
29+
const { objectName, propertyName } = matchData;
30+
if (propertyName !== word) return null;
31+
32+
const importRegex = new RegExp(`import\\s+${objectName}\\s+from\\s+['"](.*?)['"]`);
33+
const importMatch = text.match(importRegex);
34+
if (!importMatch) return null;
35+
36+
const importPath = importMatch[1];
37+
const resolvedPath = this.resolveImportPath(document, importPath);
38+
if (!resolvedPath) return null;
39+
40+
const allowedExtensions = ['.module.css', '.module.scss'];
41+
if (!allowedExtensions.some(ext => resolvedPath.endsWith(ext))) return null;
42+
43+
const fileContent = readFileSync(resolvedPath, 'utf-8');
44+
const lines = fileContent.split('\n');
45+
46+
const definitions: vscode.Location[] = [];
47+
48+
for (let i = 0; i < lines.length; i++) {
49+
let line = lines[i].trimStart();
50+
if (line.match(new RegExp(`\\.${propertyName}(?![a-zA-Z0-9-_])`))) {
51+
const definitionUri = vscode.Uri.file(resolvedPath);
52+
const definitionPosition = new vscode.Position(i, 0);
53+
definitions.push(new vscode.Location(definitionUri, definitionPosition));
54+
}
55+
}
56+
57+
return definitions;
58+
}
59+
60+
private resolveImportPath(document: vscode.TextDocument, importPath: string): string | null {
61+
const workspacePath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
62+
if (!workspacePath) return null;
63+
64+
const tsConfigPath = join(workspacePath, 'tsconfig.json');
65+
let aliasMap: Record<string, string> = {};
66+
if (existsSync(tsConfigPath)) {
67+
const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf-8'));
68+
if (tsConfig.compilerOptions?.paths) {
69+
aliasMap = this.parseTsConfigPaths(tsConfig.compilerOptions.paths, workspacePath);
70+
}
71+
}
72+
73+
for (const alias in aliasMap) {
74+
if (importPath.startsWith(alias)) {
75+
return importPath.replace(alias, aliasMap[alias]);
76+
}
77+
}
78+
79+
if (importPath.startsWith('.')) {
80+
const currentDir = join(document.uri.fsPath, '..');
81+
return resolve(currentDir, importPath);
82+
}
83+
84+
return join(workspacePath, importPath);
85+
}
86+
87+
private parseTsConfigPaths(
88+
paths: Record<string, string[]>,
89+
workspacePath: string
90+
): Record<string, string> {
91+
const aliasMap: Record<string, string> = {};
92+
for (const alias in paths) {
93+
const targetPaths = paths[alias];
94+
if (targetPaths.length > 0) {
95+
const cleanedAlias = alias.replace(/\*$/, ''); // "@/*" → "@/"
96+
const cleanedPath = targetPaths[0].replace(/\*$/, ''); // "./src/*" → "./src/"
97+
aliasMap[cleanedAlias] = join(workspacePath, cleanedPath);
98+
}
99+
}
100+
return aliasMap;
101+
}
102+
}

vscode-ext/src/diagnostics.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { exec } from 'child_process';
2+
import * as vscode from 'vscode';
3+
import { join } from 'path';
4+
5+
export const run_diag = (exec_path: string, diagnosticCollection: vscode.DiagnosticCollection) => {
6+
const workspacePath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
7+
if (!workspacePath) {
8+
return;
9+
}
10+
11+
exec(`${exec_path} --lint ${workspacePath} --minify`, (error, stdout, stderr) => {
12+
if (error || stderr) {
13+
console.error(`[CSS-linter][ERROR]: ${error || stderr}`);
14+
return;
15+
}
16+
17+
console.info(`[CSS-linter][INFO]: ${stdout}`);
18+
diagnosticCollection.clear();
19+
20+
const error_lines = stdout.split('\n');
21+
if (error_lines.length === 0) return;
22+
23+
const diagnosticsMap: Map<string, vscode.Diagnostic[]> = new Map();
24+
for (let e_line of error_lines) {
25+
let frags = e_line.split(':');
26+
if (frags.length < 4) {
27+
continue;
28+
}
29+
30+
const filePath = frags[0];
31+
const line = parseInt(frags[1]) - 1;
32+
const col = parseInt(frags[2]);
33+
const len = parseInt(frags[3]);
34+
const message = frags[4];
35+
36+
const range = new vscode.Range(line, col, line, col + len);
37+
const diagnostic = new vscode.Diagnostic(
38+
range,
39+
message,
40+
vscode.DiagnosticSeverity.Warning
41+
);
42+
diagnostic.source = 'next-css-linter';
43+
44+
const diagnostics = diagnosticsMap.get(filePath) || [];
45+
diagnostics.push(diagnostic);
46+
diagnosticsMap.set(filePath, diagnostics);
47+
}
48+
49+
diagnosticsMap.forEach((diags, file) => {
50+
const fileUri = vscode.Uri.file(
51+
join(workspacePath, file.replace(new RegExp(`^./`), ''))
52+
);
53+
diagnosticCollection.set(fileUri, diags);
54+
});
55+
});
56+
};

0 commit comments

Comments
 (0)