Skip to content

Commit e2362c4

Browse files
add interfaces and create htmlvalidator and cssvalidator classes for refactor
1 parent ec6be83 commit e2362c4

14 files changed

Lines changed: 368 additions & 211 deletions

src/class/CssValidator.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { ICssValidator } from "../interface/ICssValidator";
2+
import * as vscode from "vscode"
3+
import { CssTagTemplate } from "../interface/ICssTemplate";
4+
import * as cssService from "vscode-css-languageservice"
5+
import { TextDocument } from 'vscode-languageserver-textdocument';
6+
import { createPositions } from "../utils/createPosition";
7+
import { createVscodeDiagnostic } from "../utils/createVscodeDiagnostic";
8+
9+
10+
export class CssValidator implements ICssValidator{
11+
12+
private CssTemplateArray: Array<{ cssTemplate: CssTagTemplate }>
13+
private document: vscode.TextDocument
14+
private diagnosticCollection: vscode.Diagnostic[]
15+
private cssLanguageService:cssService.LanguageService
16+
17+
constructor(CssTemplateArray: Array<{ cssTemplate: CssTagTemplate }>,
18+
document: vscode.TextDocument,
19+
diagnosticCollection: vscode.Diagnostic[],
20+
cssLanguageService:cssService.LanguageService){
21+
22+
this.CssTemplateArray = CssTemplateArray;
23+
this.document = document;
24+
this.diagnosticCollection = diagnosticCollection;
25+
this.cssLanguageService = cssLanguageService
26+
}
27+
28+
validate():void{
29+
for (const singleBlockOfCssTemplate of this.CssTemplateArray){
30+
31+
const virtualDocumentCssLangServ = TextDocument.create(
32+
this.document.uri.toString(),
33+
'css',
34+
this.document.version,
35+
singleBlockOfCssTemplate.cssTemplate.content)
36+
37+
const diagnostic = this.cssLanguageService.doValidation(
38+
virtualDocumentCssLangServ,
39+
this.cssLanguageService.parseStylesheet(
40+
virtualDocumentCssLangServ))
41+
42+
for (const singleDiagnostic of diagnostic){
43+
44+
const diagnosticSeverity = singleDiagnostic.severity!.valueOf as unknown as vscode.DiagnosticSeverity
45+
46+
const globalOffsets = createPositions(
47+
singleBlockOfCssTemplate.cssTemplate.tag,
48+
singleBlockOfCssTemplate.cssTemplate.pos,
49+
virtualDocumentCssLangServ.offsetAt(
50+
new vscode.Position(
51+
singleDiagnostic.range.start.line,
52+
singleDiagnostic.range.start.character
53+
)
54+
),
55+
virtualDocumentCssLangServ.offsetAt(
56+
new vscode.Position(
57+
singleDiagnostic.range.end.line,
58+
singleDiagnostic.range.end.character
59+
)
60+
)
61+
);
62+
this.diagnosticCollection.push(
63+
createVscodeDiagnostic(
64+
globalOffsets.globalStartOffset,
65+
globalOffsets.globalEndOffset,
66+
singleDiagnostic.message,
67+
diagnosticSeverity,
68+
this.document
69+
)
70+
)
71+
}
72+
}
73+
}
74+
}

src/class/HtmlValidator.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import * as vscode from "vscode";
2+
import * as htmlService from "vscode-html-languageservice";
3+
import {ITagData} from "../interface/tagData"
4+
import { CustomElement } from "../class/customElement";
5+
import { HtmlTagTemplate } from "../interface/IHtmlTemplate";
6+
import {extractHtmlTagWithAttr} from "../utils/extractHtmlTagWithAttr"
7+
import { createPositions } from "../utils/createPosition";
8+
import { createVscodeDiagnostic } from "../utils/createVscodeDiagnostic";
9+
import { IHtmlValidator } from "../interface/IHtmlValidator";
10+
11+
type Parse5 = typeof import("parse5", { with: { "resolution-mode": "import" } });
12+
const htmlLanguageService = htmlService.getDefaultHTMLDataProvider();
13+
const customHtmlElements = new CustomElement();
14+
15+
export class HtmlValidator implements IHtmlValidator {
16+
private validTagNames: Set<string>;
17+
private ps: Parse5;
18+
private document: vscode.TextDocument;
19+
private diagnosticCollection: vscode.Diagnostic[];
20+
private errorCollection: vscode.DiagnosticCollection
21+
22+
constructor(
23+
ps: Parse5,
24+
document: vscode.TextDocument,
25+
diagnosticCollection: vscode.Diagnostic[]
26+
) {
27+
this.ps = ps;
28+
this.document = document;
29+
this.diagnosticCollection = diagnosticCollection;
30+
this.validTagNames = new Set(htmlLanguageService.provideTags().map(t => t.name));
31+
this.errorCollection = vscode.languages.createDiagnosticCollection("myExtension");
32+
}
33+
34+
validate(htmlTemplateArray: Array<{ htmlTemplate: HtmlTagTemplate }>): void {
35+
for (const template of htmlTemplateArray) {
36+
this.validateTemplate(template);
37+
}
38+
this.errorCollection.set(this.document.uri, this.diagnosticCollection);
39+
}
40+
41+
private validateTemplate(template: { htmlTemplate: HtmlTagTemplate }): void {
42+
const parsedHtml = this.ps.parseFragment(
43+
template.htmlTemplate.content,
44+
{ sourceCodeLocationInfo: true }
45+
);
46+
47+
for (const node of parsedHtml.childNodes) {
48+
this.validateNode(node, template);
49+
}
50+
}
51+
52+
private validateNode(node: any, template: { htmlTemplate: HtmlTagTemplate }): void {
53+
const tagData = extractHtmlTagWithAttr(node);
54+
55+
if (this.isValidTag(tagData.name)) {
56+
this.validateAttributes(tagData, template);
57+
} else if (tagData.name && tagData.name !== "#text") {
58+
this.addInvalidTagDiagnostic(tagData, template);
59+
}
60+
}
61+
62+
private isValidTag(tagName: string): boolean {
63+
return this.validTagNames.has(tagName);
64+
}
65+
66+
private validateAttributes(
67+
tagData: ITagData,
68+
template: { htmlTemplate: HtmlTagTemplate }
69+
): void {
70+
for (const attribute of tagData.attributes) {
71+
if (!this.isValidAttribute(attribute.name, tagData.name)) {
72+
this.addInvalidAttributeDiagnostic(attribute, tagData.name, template);
73+
}
74+
}
75+
}
76+
77+
private isValidAttribute(attributeName: string, tagName: string): boolean {
78+
if (attributeName === "#text") return true;
79+
80+
const validAttributeNames = new Set(
81+
htmlLanguageService.provideAttributes(tagName).map(t => t.name)
82+
);
83+
84+
const customValidAttributeNames = new Set(
85+
customHtmlElements.provideAttributes(tagName).map(t => t.name)
86+
);
87+
88+
return validAttributeNames.has(attributeName) ||
89+
customValidAttributeNames.has(attributeName);
90+
}
91+
92+
private addInvalidAttributeDiagnostic(
93+
attribute: { name: string; startOffset: number; endOffset: number },
94+
tagName: string,
95+
template: { htmlTemplate: HtmlTagTemplate }
96+
): void {
97+
const positions = createPositions(
98+
template.htmlTemplate.tag,
99+
template.htmlTemplate.pos,
100+
attribute.startOffset,
101+
attribute.endOffset
102+
);
103+
104+
this.diagnosticCollection.push(
105+
createVscodeDiagnostic(
106+
positions.globalStartOffset,
107+
positions.globalEndOffset,
108+
`Attribute ${attribute.name} is unknown or not valid for ${tagName}.`,
109+
vscode.DiagnosticSeverity.Warning,
110+
this.document
111+
)
112+
);
113+
}
114+
115+
private addInvalidTagDiagnostic(
116+
tagData: ITagData,
117+
template: { htmlTemplate: HtmlTagTemplate }
118+
): void {
119+
const positions = createPositions(
120+
template.htmlTemplate.tag,
121+
template.htmlTemplate.pos,
122+
tagData.startOffset,
123+
tagData.endOffset
124+
);
125+
126+
this.diagnosticCollection.push(
127+
createVscodeDiagnostic(
128+
positions.globalStartOffset,
129+
positions.globalEndOffset,
130+
`Tag ${tagData.name} is unknown. Check for typos.`,
131+
vscode.DiagnosticSeverity.Warning,
132+
this.document
133+
)
134+
);
135+
}
136+
}

src/class/textDocument.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)