Created
April 16, 2022 11:56
-
-
Save mizchi/1d16e46185587225d08293e069474139 to your computer and use it in GitHub Desktop.
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
import ts, { servicesVersion } from "typescript"; | |
type Files = { [key: string]: string }; | |
type SourceFiles = { [key: string]: ts.SourceFile | undefined }; | |
function createHostedProgram(rawFiles: Files, root: string[]) { | |
} | |
import fs from "fs/promises"; | |
import path from "path"; | |
// import zlib from "zlib"; | |
const tsSourcePath = path.join(__dirname, "../../node_modules/typescript/lib/"); | |
async function readLibFiles(): Promise<Files> { | |
const libFiles = await fs.readdir(tsSourcePath); | |
const entries = await Promise.all( | |
libFiles | |
.filter((file) => file.startsWith("lib.") && file.endsWith(".d.ts")) | |
.map(async (f) => { | |
const content = await fs.readFile(path.join(tsSourcePath, f), "utf8"); | |
return [`/ts/lib/${f}`, content]; | |
}) | |
); | |
return Object.fromEntries(entries); | |
} | |
// const dumpPath = path.join(__dirname, "libs.json.gz"); | |
// async function dumpLibsFile(libFiles: Files) { | |
// const zipped = zlib.gzipSync(JSON.stringify(libFiles)); | |
// await fs.writeFile(dumpPath, zipped); | |
// console.log("gen >", "libs.json.gz", zipped.length); | |
// } | |
// async function loadLibsFile(): Promise<Files> { | |
// const buf = await fs.readFile(dumpPath); | |
// const text = zlib.gunzipSync(buf).toString("utf-8"); | |
// return JSON.parse(text); | |
// } | |
const foo = 1; | |
const y = 1 + foo; | |
async function main() { | |
const libFiles = await readLibFiles(); | |
const rawFiles: Files = { | |
...libFiles, | |
"/file.ts": `const foo=1; | |
export const bar = foo + 1; | |
export const x: number = false; | |
`, | |
"/input.ts": `import { x } from "./file"; 1 as false;`, | |
}; | |
// const program = createHostedProgram({ ...libFiles, ...rawFiles }, ["/input.ts"]); | |
const compiledFiles: SourceFiles = {}; | |
const options: ts.CompilerOptions = { | |
target: ts.ScriptTarget.ESNext, | |
}; | |
const moduleResolutionHost: ts.ModuleResolutionHost = { | |
fileExists: (filePath) => !!rawFiles[filePath], | |
directoryExists: (dirPath) => dirPath === "/", | |
getDirectories: () => [], | |
readFile: (filePath) => { | |
// console.log("read", filePath); | |
return rawFiles[filePath]; | |
}, | |
} | |
// const host: ts.CompilerHost = { | |
// ...moduleResolutionHost, | |
// getCurrentDirectory: () => "/", | |
// getNewLine: () => "\n", | |
// getDefaultLibFileName: () => { | |
// return "/ts/lib/lib.esnext.d.ts"; | |
// }, | |
// getCanonicalFileName: (fileName) => fileName, | |
// getSourceFile: (filePath) => { | |
// // compile on demand | |
// const compiled = compiledFiles[filePath]; | |
// if (compiled) return compiled; | |
// compiledFiles[filePath] = ts.createSourceFile( | |
// filePath, | |
// rawFiles[filePath], | |
// ts.ScriptTarget.Latest | |
// ); | |
// return compiledFiles[filePath]; | |
// }, | |
// writeFile: (fileName, data) => { | |
// console.log("ts write >", fileName, data); | |
// }, | |
// useCaseSensitiveFileNames: () => true, | |
// }; | |
// const program = ts.createProgram({ | |
// options, | |
// rootNames: ['/input.ts'], | |
// host, | |
// }); | |
const fileVersions: ts.MapLike<{ version: number }> = {}; | |
const serviceHost: ts.LanguageServiceHost = { | |
...moduleResolutionHost, | |
// getCompilerHost() { return host; }, | |
getScriptFileNames: () => Object.keys(rawFiles), | |
getScriptVersion: fileName => | |
fileVersions[fileName] && fileVersions[fileName].version.toString(), | |
getScriptSnapshot: fileName => { | |
if (!rawFiles[fileName]) return undefined; | |
return ts.ScriptSnapshot.fromString(rawFiles[fileName]); | |
}, | |
getCurrentDirectory: () => '/', | |
getCompilationSettings: () => options, | |
getDefaultLibFileName: _options => { | |
return "/ts/lib/lib.esnext.d.ts"; | |
}, | |
useCaseSensitiveFileNames: () => true, | |
writeFile: (fileName, data) => { | |
console.log("ts write >", fileName, data); | |
}, | |
}; | |
const registry = ts.createDocumentRegistry(); | |
const service = ts.createLanguageService(serviceHost, registry); | |
const program = service.getProgram()!; | |
const checker = program.getTypeChecker(); | |
const sourceFile = program.getSourceFile('/file.ts')!; | |
const symbols = getNodes(sourceFile).map(n => checker.getSymbolAtLocation(n)); | |
// console.log(symbols); | |
for (const symbol of symbols) { | |
if(symbol == null) continue; | |
// const loc = symbol.getDeclarations()?.[0]?.getSourceFile().getLineAndCharacterOfPosition(symbol.getDeclarations()?.[0]?.getStart()); | |
// console.log(symbol?.getDeclarations()); | |
// console.log(symbol?.getDeclarations()); | |
const decls = symbol.getDeclarations(); | |
if (decls == null) continue; | |
for (const decl of decls) { | |
const range: ts.TextRange = { | |
pos: decl.getStart(sourceFile), | |
end: decl.getEnd(), | |
} | |
console.log("decls----------", ts.SyntaxKind[decl.kind], decl.getText(sourceFile)); | |
// console.log(decl); | |
const locations = service.findRenameLocations('/file.ts', decl.getStart(), true, false); | |
console.log(locations); | |
if (locations == null) continue; | |
for (const loc of locations) { | |
const s = program.getSourceFile(loc.fileName); | |
if (s == null) continue; | |
const transformed = ts.transform(s, [ | |
(context) => { | |
return (sourceFile) => { | |
// newRange.pos = newSource.getLineAndCharacterOfPosition(newRange.pos).character; | |
// newRange.end = newSource.getLineAndCharacterOfPosition(newRange.end).character; | |
// const newText = newSource.getText().substring(newRange.pos, newRange.end); | |
// console.log("newText", newText); | |
// newSource.text = newSource.text.substring(0, newRange.pos) + newText + newSource.text.substring(newRange.end); | |
// return newSource; | |
// // } | |
const visit = (node: ts.Node) => { | |
return node; | |
}; | |
return ts.factory.updateSourceFile(sourceFile, ts.visitNodes(sourceFile.statements, visit)) | |
} | |
} | |
]); | |
const newSource = transformed.transformed[0]; | |
console.log(newSource.getFullText()); | |
// return this.documentRegistry.createOrUpdateSourceFile(filePath, this.context.compilerOptions.get(), ts.ScriptSnapshot.fromString(text), scriptKind); | |
// transformed.transformed | |
// registry.updateDocument(loc.fileName, {}, transformed.transformed[0], "1", ts.ScriptKind.TSX); | |
}; | |
// const edits = service.getEditsForFileRename('/file.ts', '/file2.ts', {}, undefined); | |
// const refactors = service.getApplicableRefactors('/file.ts', range, undefined); | |
// console.log(refactors?.[0]); | |
// const edits = service.getEditsForRefactor('/file.ts', {}, range, 'rename', 'newName', undefined); | |
// console.log(locations); | |
// console.log(edits?.[0].actions); | |
// service.findReferences(decl.) | |
// const renameInfo = service.getRenameInfo('/file.ts', decl.getStart(sourceFile)); | |
// console.log(renameInfo); | |
// service.applyCodeActionCommand(renameInfo); | |
// service.getRenameInfo(decl, 0); | |
} | |
// symbol.getRena | |
} | |
// service.getRenameInfo(program, ) | |
// const p = service.findReferences('/input.ts', 0); | |
// const program = service.getProgram()!; | |
// const refs = service.getFileReferences('/file.ts'); | |
// const refs = service.findReferences('/input.ts', 5); | |
// console.log(refs); | |
// program. | |
// const refs = program.getProjectReferences(); | |
// console.log(refs); | |
// console.log(program); | |
// console.log(service); | |
// const out = service.getEmitOutput("/input.ts"); | |
// console.log("out", out); | |
// program.get | |
// const files = program.getSourceFiles(); | |
// // ts.createLanguageService(host) | |
// for (const file of files) { | |
// if (!file.fileName.includes("/ts/lib/")) { | |
// console.log(file.fileName, `\n` + file.text); | |
// } | |
// } | |
// const checker = program.getTypeChecker(); | |
// checker.getPre | |
// console.log(program.getCurrentDirectory());; | |
// console.log(program.getSymbolCount()); | |
// // program.getSourceFile() | |
// const source = program.getSourceFile('/input.ts'); | |
// source?.statements.forEach((node) => { | |
// console.log(node); | |
// // node.sy | |
// }); | |
// ts. | |
// ts.visitEachChild(source, (node) => { | |
// return node; | |
// }, {}); | |
// program. | |
// const ret = ts.getPreEmitDiagnostics(program); | |
// for (const d of ret) { | |
// // @ts-ignore | |
// console.log(d.file?.fileName, '~', d.messageText); | |
// } | |
} | |
const getNodes = (sf: ts.SourceFile): ts.Identifier[] => { | |
const nodes: ts.Identifier[] = []; | |
const allNodes = (n: ts.Node) => { | |
ts.forEachChild(n, n => { | |
ts.isIdentifier(n) && nodes.push(n); | |
allNodes(n); | |
return false; | |
}) | |
}; | |
allNodes(sf); | |
return nodes; | |
} | |
main().catch((e) => console.error(e)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment