Skip to content

Commit

Permalink
Refactor rule modules and add component analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
runem committed May 6, 2020
1 parent 4d95d77 commit 950d0e3
Show file tree
Hide file tree
Showing 112 changed files with 1,635 additions and 2,119 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ComponentDefinition } from "web-component-analyzer";
import { LitAnalyzerContext } from "../lit-analyzer-context";
import { LitCodeFix } from "../types/lit-code-fix";
import { LitDiagnostic } from "../types/lit-diagnostic";
import { SourceFileRange } from "../types/range";
import { arrayDefined, arrayFlat } from "../util/array-util";
import { intersects } from "../util/range-util";
import { convertRuleDiagnosticToLitDiagnostic } from "../util/rule-diagnostic-util";
import { converRuleFixToLitCodeFix } from "../util/rule-fix-util";

export class ComponentAnalyzer {
getDiagnostics(definition: ComponentDefinition, context: LitAnalyzerContext): LitDiagnostic[] {
return context.rules.getDiagnosticsFromDefinition(definition, context).map(d => convertRuleDiagnosticToLitDiagnostic(d, context));
}

getCodeFixesAtOffsetRange(definition: ComponentDefinition, range: SourceFileRange, context: LitAnalyzerContext): LitCodeFix[] {
return arrayFlat(
arrayDefined(
context.rules
.getDiagnosticsFromDefinition(definition, context)
.filter(({ diagnostic }) => intersects(range, diagnostic.location))
.map(({ diagnostic }) => diagnostic.fix?.())
)
).map(ruleFix => converRuleFixToLitCodeFix(ruleFix));
}
}
32 changes: 26 additions & 6 deletions packages/lit-analyzer/src/analyze/default-lit-analyzer-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { analyzeHTMLElement, analyzeSourceFile } from "web-component-analyzer";
import noBooleanInAttributeBindingRule from "../rules/no-boolean-in-attribute-binding";
import noComplexAttributeBindingRule from "../rules/no-complex-attribute-binding";
import noExpressionlessPropertyBindingRule from "../rules/no-expressionless-property-binding";
import noIncompatiblePropertyType from "../rules/no-incompatible-property-type";
import noIncompatibleTypeBindingRule from "../rules/no-incompatible-type-binding";
import noInvalidAttributeName from "../rules/no-invalid-attribute-name";
import noInvalidDirectiveBindingRule from "../rules/no-invalid-directive-binding";
import noIncompatiblePropertyType from "../rules/no-incompatible-property-type";
import noInvalidTagName from "../rules/no-invalid-tag-name";
import noMissingImport from "../rules/no-missing-import";
import noNoncallableEventBindingRule from "../rules/no-noncallable-event-binding";
Expand All @@ -27,16 +27,17 @@ import { LitAnalyzerContext, LitPluginContextHandler } from "./lit-analyzer-cont
import { DefaultLitAnalyzerLogger, LitAnalyzerLoggerLevel } from "./lit-analyzer-logger";
import { convertAnalyzeResultToHtmlCollection, convertComponentDeclarationToHtmlTag } from "./parse/convert-component-definitions-to-html-collection";
import { parseDependencies } from "./parse/parse-dependencies/parse-dependencies";
import { RuleCollection } from "./rule-collection";
import { DefaultAnalyzerDefinitionStore } from "./store/definition-store/default-analyzer-definition-store";
import { DefaultAnalyzerDependencyStore } from "./store/dependency-store/default-analyzer-dependency-store";
import { DefaultAnalyzerDocumentStore } from "./store/document-store/default-analyzer-document-store";
import { DefaultAnalyzerHtmlStore } from "./store/html-store/default-analyzer-html-store";
import { HtmlDataSourceKind } from "./store/html-store/html-data-source-merged";
import { RuleModule } from "./types/rule-module";
import { RuleModule } from "./types/rule/rule-module";
import { changedSourceFileIterator } from "./util/changed-source-file-iterator";
import { iterableFirst } from "./util/iterable-util";

const rules: RuleModule[] = [
const ALL_RULES: RuleModule[] = [
noExpressionlessPropertyBindingRule,
noUnintendedMixedBindingRule,
noUnknownSlotRule,
Expand Down Expand Up @@ -78,14 +79,33 @@ export class DefaultLitAnalyzerContext implements LitAnalyzerContext {
return this._config;
}

private _currentFile: SourceFile | undefined;
get currentFile(): SourceFile {
if (this._currentFile == null) {
throw new Error("Current file is not set");
}

return this._currentFile;
}

readonly htmlStore = new DefaultAnalyzerHtmlStore();
readonly dependencyStore = new DefaultAnalyzerDependencyStore();
readonly documentStore = new DefaultAnalyzerDocumentStore();
readonly definitionStore = new DefaultAnalyzerDefinitionStore();
readonly logger = new DefaultLitAnalyzerLogger();

get rules(): RuleModule[] {
return rules;
private _rules: RuleCollection | undefined;
get rules(): RuleCollection {
if (this._rules == null) {
this._rules = new RuleCollection();
this._rules.push(...ALL_RULES);
}

return this._rules;
}

public setCurrentFile(file: SourceFile | undefined): void {
this._currentFile = file;
}

public updateConfig(config: LitAnalyzerConfig) {
Expand Down Expand Up @@ -170,7 +190,7 @@ export class DefaultLitAnalyzerContext implements LitAnalyzerContext {
config: {
features: ["event", "member", "slot"],
analyzeGlobalFeatures: true,
analyzeLibDom: false,
analyzeLibDom: true,
analyzeLib: true,
excludedDeclarationNames: ["HTMLElement"]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { LitAnalyzerContext } from "../../lit-analyzer-context";
import { CssDocument } from "../../parse/document/text-document/css-document/css-document";
import { getPositionContextInDocument } from "../../util/get-position-context-in-document";
import { LitAnalyzerRequest } from "../../lit-analyzer-context";
import { LitCompletion } from "../../types/lit-completion";
import { LitCompletionDetails } from "../../types/lit-completion-details";
import { DefinitionKind, LitDefinition } from "../../types/lit-definition";
import { LitCssDiagnostic } from "../../types/lit-diagnostic";
import { LitDiagnostic } from "../../types/lit-diagnostic";
import { LitQuickInfo } from "../../types/lit-quick-info";
import { DocumentOffset } from "../../types/range";
import { getPositionContextInDocument } from "../../util/get-position-context-in-document";
import { documentRangeToSFRange } from "../../util/range-util";
import { LitCssVscodeService } from "./lit-css-vscode-service";

export class LitCssDocumentAnalyzer {
private vscodeCssService = new LitCssVscodeService();
private completionsCache: LitCompletion[] = [];

getCompletionDetailsAtOffset(document: CssDocument, offset: number, name: string, request: LitAnalyzerRequest): LitCompletionDetails | undefined {
getCompletionDetailsAtOffset(
document: CssDocument,
offset: DocumentOffset,
name: string,
context: LitAnalyzerContext
): LitCompletionDetails | undefined {
const completionWithName = this.completionsCache.find(completion => completion.name === name);

if (completionWithName == null || completionWithName.documentation == null) return undefined;
Expand All @@ -27,33 +34,33 @@ export class LitCssDocumentAnalyzer {
};
}

getCompletionsAtOffset(document: CssDocument, offset: number, request: LitAnalyzerRequest): LitCompletion[] {
this.completionsCache = this.vscodeCssService.getCompletions(document, offset, request);
getCompletionsAtOffset(document: CssDocument, offset: DocumentOffset, context: LitAnalyzerContext): LitCompletion[] {
this.completionsCache = this.vscodeCssService.getCompletions(document, offset, context);
return this.completionsCache;
}

getQuickInfoAtOffset(document: CssDocument, offset: number, request: LitAnalyzerRequest): LitQuickInfo | undefined {
return this.vscodeCssService.getQuickInfo(document, offset, request);
getQuickInfoAtOffset(document: CssDocument, offset: DocumentOffset, context: LitAnalyzerContext): LitQuickInfo | undefined {
return this.vscodeCssService.getQuickInfo(document, offset, context);
}

getDiagnostics(document: CssDocument, request: LitAnalyzerRequest): LitCssDiagnostic[] {
return this.vscodeCssService.getDiagnostics(document, request);
getDiagnostics(document: CssDocument, context: LitAnalyzerContext): LitDiagnostic[] {
return this.vscodeCssService.getDiagnostics(document, context);
}

getDefinitionAtOffset(document: CssDocument, offset: number, request: LitAnalyzerRequest): LitDefinition | undefined {
getDefinitionAtOffset(document: CssDocument, offset: DocumentOffset, context: LitAnalyzerContext): LitDefinition | undefined {
const positionContext = getPositionContextInDocument(document, offset);
const tagNameMatch = positionContext.word.match(/^[a-zA-Z-1-9]+/);
if (tagNameMatch == null) return undefined;
const tagName = tagNameMatch[0];
const definition = request.definitionStore.getDefinitionForTagName(tagName);
const definition = context.definitionStore.getDefinitionForTagName(tagName);

if (definition != null) {
const start = offset - positionContext.leftWord.length;
const end = start + tagName.length;

return {
kind: DefinitionKind.COMPONENT,
fromRange: { document, start, end },
fromRange: documentRangeToSFRange(document, { start, end }),
target: definition.declaration()
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import * as vscode from "vscode-css-languageservice";
import { IAtDirectiveData, ICSSDataProvider, IPropertyData, IPseudoClassData, IPseudoElementData } from "vscode-css-languageservice";
import { isRuleDisabled } from "../../lit-analyzer-config";
import { LitAnalyzerRequest } from "../../lit-analyzer-context";
import { LitAnalyzerContext } from "../../lit-analyzer-context";
import { CssDocument } from "../../parse/document/text-document/css-document/css-document";
import { AnalyzerHtmlStore } from "../../store/analyzer-html-store";
import { LitCompletion } from "../../types/lit-completion";
import { LitCssDiagnostic } from "../../types/lit-diagnostic";
import { LitDiagnostic } from "../../types/lit-diagnostic";
import { LitQuickInfo } from "../../types/lit-quick-info";
import { LitTargetKind } from "../../types/lit-target-kind";
import { DocumentOffset } from "../../types/range";
import { lazy } from "../../util/general-util";
import { iterableFilter, iterableMap } from "../../util/iterable-util";
import { documentRangeToSFRange } from "../../util/range-util";

function makeVscTextDocument(cssDocument: CssDocument): vscode.TextDocument {
return vscode.TextDocument.create("untitled://embedded.css", "css", 1, cssDocument.virtualDocument.text);
Expand All @@ -26,7 +28,7 @@ export class LitCssVscodeService {
return vscode.getSCSSLanguageService({ customDataProviders: [this.dataProvider.provider] });
}

getDiagnostics(document: CssDocument, context: LitAnalyzerRequest): LitCssDiagnostic[] {
getDiagnostics(document: CssDocument, context: LitAnalyzerContext): LitDiagnostic[] {
this.dataProvider.update(context.htmlStore);

const vscTextDocument = makeVscTextDocument(document);
Expand All @@ -50,17 +52,18 @@ export class LitCssVscodeService {
diagnostic =>
({
severity: diagnostic.severity === vscode.DiagnosticSeverity.Error ? "error" : "warning",
location: {
document,
source: "no-invalid-css",
location: documentRangeToSFRange(document, {
start: vscTextDocument.offsetAt(diagnostic.range.start),
end: vscTextDocument.offsetAt(diagnostic.range.end)
},
message: diagnostic.message
} as LitCssDiagnostic)
}),
message: diagnostic.message,
file: context.currentFile
} as LitDiagnostic)
);
}

getQuickInfo(document: CssDocument, offset: number, context: LitAnalyzerRequest): LitQuickInfo | undefined {
getQuickInfo(document: CssDocument, offset: DocumentOffset, context: LitAnalyzerContext): LitQuickInfo | undefined {
this.dataProvider.update(context.htmlStore);

const vscTextDocument = makeVscTextDocument(document);
Expand Down Expand Up @@ -88,16 +91,12 @@ export class LitCssVscodeService {
return {
primaryInfo: primaryInfo || "",
secondaryInfo,
range: {
document,
start: vscTextDocument.offsetAt(hover.range.start),
end: vscTextDocument.offsetAt(hover.range.end)
}
range: documentRangeToSFRange(document, { start: vscTextDocument.offsetAt(hover.range.start), end: vscTextDocument.offsetAt(hover.range.end) })
};
}

getCompletions(document: CssDocument, offset: number, request: LitAnalyzerRequest): LitCompletion[] {
this.dataProvider.update(request.htmlStore);
getCompletions(document: CssDocument, offset: DocumentOffset, context: LitAnalyzerContext): LitCompletion[] {
this.dataProvider.update(context.htmlStore);

const vscTextDocument = makeVscTextDocument(document);
const vscStylesheet = this.makeVscStylesheet(vscTextDocument);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { LitAnalyzerContext } from "../../../lit-analyzer-context";
import { HtmlDocument } from "../../../parse/document/text-document/html-document/html-document";
import { LitCodeFix } from "../../../types/lit-code-fix";
import { DocumentRange } from "../../../types/range";
import { arrayDefined, arrayFlat } from "../../../util/array-util";
import { documentRangeToSFRange, intersects } from "../../../util/range-util";
import { converRuleFixToLitCodeFix } from "../../../util/rule-fix-util";

export function codeFixesForHtmlDocument(htmlDocument: HtmlDocument, range: DocumentRange, context: LitAnalyzerContext): LitCodeFix[] {
return arrayFlat(
arrayDefined(
context.rules
.getDiagnosticsFromDocument(htmlDocument, context)
.filter(({ diagnostic }) => intersects(documentRangeToSFRange(htmlDocument, range), diagnostic.location))
.map(({ diagnostic }) => diagnostic.fix?.())
)
).map(ruleFix => converRuleFixToLitCodeFix(ruleFix));
}
Loading

0 comments on commit 950d0e3

Please sign in to comment.