Skip to content

Commit

Permalink
fix(vls): should preserve error after editing file without error
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework committed Feb 6, 2022
1 parent 7a0316a commit 13e97be
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 34 deletions.
4 changes: 2 additions & 2 deletions packages/vite-plugin-checker/src/Checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if (!isMainThread) {
}

export interface CheckerMeta<T extends BuildInCheckerNames> {
name: string
name: T
absFilePath: string
createDiagnostic: CreateDiagnostic<T>
build: ServeAndBuildChecker['build']
Expand All @@ -31,7 +31,7 @@ export abstract class Checker<T extends BuildInCheckerNames> implements CheckerM
this.logger.forEach((fn) => fn(...args))
}

public name: string
public name: T
public absFilePath: string
public createDiagnostic: CreateDiagnostic<T>
public build: ServeAndBuildChecker['build']
Expand Down
38 changes: 38 additions & 0 deletions packages/vite-plugin-checker/src/DiagnosticCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { NormalizedDiagnostic } from './logger'

class FileDiagnosticCache {
public diagnostics: NormalizedDiagnostic[] = []

public initWith(diagnostics: NormalizedDiagnostic[]) {
diagnostics.forEach((d) => {
this.diagnostics.push(d)
})
}

public getDiagnostics(fileName?: string) {
if (fileName) {
return this.diagnostics.filter((f) => f.id === fileName)
}

return this.diagnostics
}

public get lastDiagnostic() {
return this.diagnostics[this.diagnostics.length - 1]
}

public setFile(fileName: string, next: NormalizedDiagnostic[] | null) {
for (let i = 0; i < this.diagnostics.length; i++) {
if (this.diagnostics[i].id === fileName) {
this.diagnostics.splice(i, 1)
i--
}
}

if (next?.length) {
this.diagnostics.push(...next)
}
}
}

export { FileDiagnosticCache }
2 changes: 1 addition & 1 deletion packages/vite-plugin-checker/src/checkers/eslint/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const createDiagnostic: CreateDiagnostic<'eslint'> = (pluginConfig) => {
export class EslintChecker extends Checker<'eslint'> {
public constructor() {
super({
name: 'typescript',
name: 'eslint',
absFilePath: __filename,
build: {
buildBin: (pluginConfig) => {
Expand Down
12 changes: 9 additions & 3 deletions packages/vite-plugin-checker/src/checkers/typescript/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,14 @@ const createDiagnostic: CreateDiagnostic<'typescript'> = (pluginConfig) => {
// https://github.com/microsoft/TypeScript/pull/33082/files
const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram

if (typeof pluginConfig.typescript === 'object' && pluginConfig.typescript.buildMode) {
const host = ts.createSolutionBuilderWithWatchHost(ts.sys, createProgram, reportDiagnostic, undefined, reportWatchStatusChanged)
if (typeof pluginConfig.typescript === 'object' && pluginConfig.typescript.buildMode) {
const host = ts.createSolutionBuilderWithWatchHost(
ts.sys,
createProgram,
reportDiagnostic,
undefined,
reportWatchStatusChanged
)

ts.createSolutionBuilderWithWatch(host, [configFile], {}).build()
} else {
Expand All @@ -118,7 +124,7 @@ const createDiagnostic: CreateDiagnostic<'typescript'> = (pluginConfig) => {
reportDiagnostic,
reportWatchStatusChanged
)

ts.createWatchProgram(host)
}
},
Expand Down
81 changes: 54 additions & 27 deletions packages/vite-plugin-checker/src/checkers/vls/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Diagnostic,
DiagnosticSeverity,
DidChangeTextDocumentNotification,
DidChangeWatchedFilesNotification,
DidOpenTextDocumentNotification,
InitializeParams,
InitializeRequest,
Expand All @@ -32,11 +33,11 @@ import {
normalizeLspDiagnostic,
normalizePublishDiagnosticParams,
} from '../../logger'
import { DeepPartial } from '../../types'
import { getInitParams, VlsOptions } from './initParams'

import type { ErrorPayload } from 'vite'
import { DeepPartial } from '../../types'

import { FileDiagnosticCache } from '../../DiagnosticCache'
enum DOC_VERSION {
init = -1,
}
Expand All @@ -45,6 +46,7 @@ export type LogLevel = typeof logLevels[number]
export const logLevels = ['ERROR', 'WARN', 'INFO', 'HINT'] as const

let disposeSuppressConsole: ReturnType<typeof suppressConsole>
const diagnosticCache = new FileDiagnosticCache()

export const logLevel2Severity = {
ERROR: DiagnosticSeverity.Error,
Expand Down Expand Up @@ -89,12 +91,12 @@ export async function diagnostics(

// initial report
if (!errCount) {
consoleLogVls(chalk.green(`[VLS checker] No error found`))
vlsConsoleLog(chalk.green(`[VLS checker] No error found`))
if (!watch) {
process.exit(0)
}
} else {
consoleLogVls(
vlsConsoleLog(
chalk.red(`[VLS checker] Found ${errCount} ${errCount === 1 ? 'error' : 'errors'}`)
)
if (!watch) {
Expand All @@ -118,18 +120,18 @@ export class TestStream extends Duplex {
public _read(_size: number) {}
}

let consoleLogVls = consoleLog
let vlsConsoleLog = consoleLog

function suppressConsole() {
let disposed = false
const rawConsoleLog = consoleLogVls
consoleLogVls = () => {}
const rawConsoleLog = vlsConsoleLog
vlsConsoleLog = () => {}

return () => {
if (disposed) return

disposed = true
consoleLogVls = rawConsoleLog
vlsConsoleLog = rawConsoleLog
}
}

Expand Down Expand Up @@ -160,27 +162,27 @@ export async function prepareClientConnection(
return
}

const absFilePath = URI.parse(publishDiagnostics.uri).fsPath
publishDiagnostics.diagnostics = filterDiagnostics(publishDiagnostics.diagnostics, severity)
const nextDiagnosticInFile = await normalizePublishDiagnosticParams(publishDiagnostics)
diagnosticCache.setFile(absFilePath, nextDiagnosticInFile)

if (!publishDiagnostics.diagnostics.length) {
return
}

publishDiagnostics.diagnostics = filterDiagnostics(publishDiagnostics.diagnostics, severity)
const res = await normalizePublishDiagnosticParams(publishDiagnostics)
const normalized = diagnosticToViteError(res)
consoleLogVls(os.EOL)
consoleLogVls(res.map((d) => diagnosticToTerminalLog(d, 'VLS')).join(os.EOL))
const res = diagnosticCache.getDiagnostics()
vlsConsoleLog(os.EOL)
vlsConsoleLog(res.map((d) => diagnosticToTerminalLog(d, 'VLS')).join(os.EOL))

options.errorCallback?.(publishDiagnostics, normalized)
if (diagnosticCache.lastDiagnostic) {
const normalized = diagnosticToViteError(diagnosticCache.lastDiagnostic)
options.errorCallback?.(publishDiagnostics, normalized)
}
}

const vls = new VLS(serverConnection as any)

vls.validateTextDocument = async (textDocument: TextDocument, cancellationToken?: any) => {
const diagnostics = await vls.doValidate(textDocument, cancellationToken)
if (diagnostics) {
// @ts-ignore
// @ts-expect-error
vls.lspConnection.sendDiagnostics({
uri: textDocument.uri,
version: textDocument.version,
Expand Down Expand Up @@ -217,14 +219,26 @@ export async function prepareClientConnection(
return { clientConnection, serverConnection, vls, up, down, logger }
}

function extToGlobs(exts: string[]) {
return exts.map((e) => '**/*' + e)
}

const watchedDidChangeContent = ['.vue']
const watchedDidChangeWatchedFiles = ['.js', '.ts', '.json']
const watchedDidChangeContentGlob = extToGlobs(watchedDidChangeContent)
const watchedDidChangeWatchedFilesGlob = extToGlobs(watchedDidChangeWatchedFiles)

async function getDiagnostics(
workspaceUri: URI,
severity: DiagnosticSeverity,
options: DiagnosticOptions
) {
const { clientConnection } = await prepareClientConnection(workspaceUri, severity, options)

const files = glob.sync('**/*.vue', { cwd: workspaceUri.fsPath, ignore: ['node_modules/**'] })
const files = glob.sync([...watchedDidChangeContentGlob, ...watchedDidChangeWatchedFilesGlob], {
cwd: workspaceUri.fsPath,
ignore: ['node_modules/**'],
})

if (files.length === 0) {
console.log('No input files')
Expand Down Expand Up @@ -259,7 +273,7 @@ async function getDiagnostics(
},
})

// logout in build mode
// log in build mode
if (!options.watch) {
try {
let diagnostics = (await clientConnection.sendRequest('$/getDiagnostics', {
Expand Down Expand Up @@ -305,21 +319,34 @@ async function getDiagnostics(
})

watcher.add(workspaceUri.fsPath)
watcher.on('all', async (event, path) => {
if (!path.endsWith('.vue')) return
const fileContent = await fs.promises.readFile(path, 'utf-8')
// TODO: watch js change
watcher.on('all', async (event, filePath) => {
const extname = path.extname(filePath)
// .vue file changed
if (!filePath.endsWith('.vue')) return
const fileContent = await fs.promises.readFile(filePath, 'utf-8')
clientConnection.sendNotification(DidChangeTextDocumentNotification.type, {
textDocument: {
uri: URI.file(path).toString(),
uri: URI.file(filePath).toString(),
version: Date.now(),
},
contentChanges: [{ text: fileContent }],
})

// .js,.ts,.json file changed
if (watchedDidChangeWatchedFiles.includes(extname)) {
clientConnection.sendNotification(DidChangeWatchedFilesNotification.type, {
changes: [
{
uri: URI.file(filePath).toString(),
type: event === 'add' ? 1 : event === 'unlink' ? 3 : 2,
},
],
})
}
})
}

consoleLogVls(logChunk)
vlsConsoleLog(logChunk)
return initialErrCount
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vite-plugin-checker/src/checkers/vueTsc/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const createDiagnostic: CreateDiagnostic<'vueTsc'> = (pluginConfig) => {
export class VueTscChecker extends Checker<'vueTsc'> {
public constructor() {
super({
name: 'typescript',
name: 'vueTsc',
absFilePath: __filename,
build: { buildBin: ['vue-tsc', ['--noEmit']] },
createDiagnostic,
Expand Down

0 comments on commit 13e97be

Please sign in to comment.