-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support programmatic type check
- Loading branch information
Showing
3 changed files
with
195 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import ts from 'typescript' | ||
import type { UserConfig, ViteDevServer } from 'vite' | ||
|
||
interface DiagnoseOptions { | ||
root: string | ||
tsconfigPath: string | ||
} | ||
|
||
const formatHost: ts.FormatDiagnosticsHost = { | ||
getCanonicalFileName: (path) => path, | ||
getCurrentDirectory: ts.sys.getCurrentDirectory, | ||
getNewLine: () => ts.sys.newLine, | ||
} | ||
|
||
function reportDiagnostic(diagnostic: ts.Diagnostic) { | ||
console.error( | ||
'Error', | ||
diagnostic.code, | ||
':', | ||
ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine()) | ||
) | ||
} | ||
|
||
/** | ||
* Prints a diagnostic every time the watch status changes. | ||
* This is mainly for messages like "Starting compilation" or "Compilation completed". | ||
*/ | ||
function reportWatchStatusChanged(diagnostic: ts.Diagnostic) { | ||
console.info(ts.formatDiagnostic(diagnostic, formatHost)) | ||
} | ||
|
||
export function createDiagnosis(userOptions: Partial<DiagnoseOptions> = {}) { | ||
let overlay = true // Vite default to true | ||
let err: string | null = null | ||
|
||
return { | ||
config: (config: UserConfig) => { | ||
const hmr = config.server?.hmr | ||
if (typeof hmr === 'object' && hmr.overlay === false) { | ||
overlay = true | ||
} | ||
}, | ||
configureServer(server: ViteDevServer) { | ||
const finalConfig: DiagnoseOptions = { | ||
root: process.cwd(), | ||
tsconfigPath: 'tsconfig.json', | ||
...userOptions, | ||
} | ||
|
||
const configFile = ts.findConfigFile( | ||
finalConfig.root, | ||
ts.sys.fileExists, | ||
finalConfig.tsconfigPath | ||
) | ||
|
||
if (!configFile) { | ||
throw new Error("Could not find a valid 'tsconfig.json'.") | ||
} | ||
|
||
// const { config } = ts.readConfigFile(configFile, ts.sys.readFile) | ||
// const { options } = ts.parseJsonConfigFileContent(config, ts.sys, finalConfig.root) | ||
// force --noEmit | ||
// options.noEmit = true | ||
|
||
// https://github.com/microsoft/TypeScript/issues/32385 | ||
const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram | ||
const host = ts.createWatchCompilerHost( | ||
configFile, | ||
{ noEmit: true }, | ||
ts.sys, | ||
createProgram, | ||
reportDiagnostic, | ||
reportWatchStatusChanged | ||
) | ||
|
||
// You can technically override any given hook on the host, though you probably | ||
// don't need to. | ||
// Note that we're assuming `origCreateProgram` and `origPostProgramCreate` | ||
// doesn't use `this` at all. | ||
// const origCreateProgram = host.createProgram | ||
// @ts-ignore | ||
// host.createProgram = (rootNames: ReadonlyArray<string>, options, host, oldProgram) => { | ||
// console.log("** We're about to create the program! **") | ||
// return origCreateProgram(rootNames, options, host, oldProgram) | ||
// } | ||
|
||
// const origPostProgramCreate = host.afterProgramCreate | ||
|
||
// host.afterProgramCreate = (program) => { | ||
// console.log('** We finished making the program! **') | ||
// origPostProgramCreate!(program) | ||
// } | ||
|
||
// `createWatchProgram` creates an initial program, watches files, and updates | ||
// the program over time. | ||
ts.createWatchProgram(host) | ||
}, | ||
} | ||
} | ||
|
||
export const diagnose = createDiagnosis() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import ts from 'typescript' | ||
import type { UserConfig, ViteDevServer } from 'vite' | ||
import { exec, ChildProcess, spawn } from 'child_process' | ||
|
||
const placeHolders = { | ||
tscStart: '', | ||
tscEnd: ' error.', | ||
tscWatchStart: 'File change detected. Starting incremental compilation...', | ||
tscWatchEnd: '. Watching for file changes.', | ||
} | ||
|
||
function findOutputEnd(data: string): null | number { | ||
const regResult = /Found (\d+) error. Watching for file changes/.exec(data) | ||
if (!regResult) return null | ||
return Number(regResult[1]) | ||
} | ||
|
||
function createTscProcess() { | ||
let overlay = true // Vite default to true | ||
let err: string | null = null | ||
|
||
return { | ||
config: (config: UserConfig) => { | ||
const hmr = config.server?.hmr | ||
if (typeof hmr === 'object' && hmr.overlay === false) { | ||
overlay = true | ||
} | ||
}, | ||
configureServer: (server: ViteDevServer) => { | ||
const tsProc = exec('tsc --noEmit --watch', { cwd: server.config.root }) | ||
// const tsProc = spawn('tsc', ['--noEmit', '--watch'], { cwd: root, stdio: 'pipe' }) | ||
// diagnosticCount++ | ||
tsProc.stdout!.on('data', (data) => { | ||
const dataStr = data.toString() | ||
const parsedError = findOutputEnd(dataStr) | ||
if (parsedError === 0 || parsedError === null) { | ||
err = null | ||
if (!overlay) return | ||
server.ws.send({ | ||
type: 'update', | ||
updates: [], | ||
}) | ||
return | ||
} | ||
|
||
if (parsedError > 0) { | ||
err = dataStr | ||
if (!overlay) return | ||
server.ws.send({ | ||
type: 'error', | ||
err: { | ||
message: 'error msg', | ||
stack: 'a/b/c/d', | ||
id: 'fork-ts-checker', | ||
frame: 'frame', | ||
plugin: 'tsc', | ||
pluginCode: 'code', | ||
// loc: , | ||
}, | ||
}) | ||
return | ||
} | ||
|
||
// do not clear stdout | ||
// if (dataStr === '\x1Bc') return | ||
// console.log(data) | ||
// process.stdout.pipe(data) | ||
}) | ||
}, | ||
} | ||
} | ||
|
||
export const tscProcess = createTscProcess() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters