- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
意图
我想使用 TypeScript 的 Compiler API在 TypeScript 代码中试验运算符重载。具体来说,我想找到 x + y
的所有实例并将它们变成 op_add(x, y)
.但是,我希望语言服务(例如 VS Code 中的 IntelliSense)了解转换并显示正确的类型。
例如在这段代码中:
interface Vector2 { x: number, y: number }
declare function op_add(x: Vector2, y: Vector2): Vector2
declare let a: Vector2, b: Vector2
let c = a + b
我希望当我将鼠标悬停在
c
上时,它会显示
Vector2
.
typescript
相同的 API 的程序– 以同样的方式 ttypescript
做。 typescript
之前,让该程序修改源代码typescript
compile.ts
的简短脚本。使用编译器 API 解析名为
sample.ts
的文件进入
AST .然后直接修改AST,改变
Binary(x, PlusToken, y)
至
Call(op_add, x, y)
.最后,它将修改后的代码打印到控制台,然后尝试发出。对于 IDE 集成而言,仅此是不够的,但这是一个好的开始。
compile.ts
:
import * as ts from "typescript"
import { possibleChildProperties } from "./visit";
let program = ts.createProgram(['sample.ts'], { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS })
let inputFiles = program.getSourceFiles()
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
let outputCode: string
for (let input of inputFiles) {
if (input.fileName === 'sample.ts') {
ts.visitNode(input, visitor) // modifies input's AST
outputCode = printer.printNode(ts.EmitHint.Unspecified, input, input)
break
}
}
console.log(outputCode) // works
let emitResult = program.emit() // fails
function visitor(node: ts.Node): ts.Node {
if (node.kind === ts.SyntaxKind.BinaryExpression) {
let expr = node as ts.BinaryExpression
if (expr.operatorToken.kind === ts.SyntaxKind.PlusToken) {
return ts.createCall(ts.createIdentifier('op_add'), [], [expr.left, expr.right])
}
}
return visitChildren(node, visitor)
}
function visitChildren(node: ts.Node, visitor: ts.Visitor) {
for (const prop of possibleChildProperties) {
if (node[prop] !== undefined) {
if (Array.isArray(node[prop]))
node[prop] = node[prop].map(visitor)
else
node[prop] = visitor(node[prop])
}
}
return node
}
sample.ts
:
let a = { a: 4 }
let b = { b: 3 }
let c = a + b
console.log
输出:
let a = { a: 4 };
let b = { b: 3 };
let c = op_add(a, b);
program.emit()
导致未指定的内部错误。这可能意味着我正在以不受支持的方式修改 AST。
/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:100920
throw e;
^
Error: start < 0
at createTextSpan (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:10559:19)
at Object.createTextSpanFromBounds (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:10568:16)
at getErrorSpanForNode (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:13914:19)
at createDiagnosticForNodeInSourceFile (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:13808:20)
at Object.createDiagnosticForNode (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:13799:16)
at error (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:35703:22)
at resolveNameHelper (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:36602:29)
at resolveName (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:36274:20)
at getResolvedSymbol (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:52602:21)
at checkIdentifier (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:54434:26)
ts.visitEachChild
只能在类型检查后使用。并且自己深度克隆节点似乎也不是一个可行的选择,因为没有任何方法可以创建
Program
来自代码生成的 AST。
sample.ts
缺少
op_add
的声明,这可能会导致问题。我将此行添加到文件的顶部:
declare function op_add(x: {}, y: {}): string
现在有一个不同的错误——文件诊断的生成失败:
/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:100920
throw e;
^
Error: Debug Failure. Expected -2 >= 0
at Object.createFileDiagnostic (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:17868:18)
at grammarErrorAtPos (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:69444:36)
at checkGrammarForAtLeastOneTypeArgument (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:68771:24)
at checkGrammarTypeArguments (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:68777:17)
at checkCallExpression (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:59255:18)
at checkExpressionWorker (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:61687:28)
at checkExpression (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:61597:38)
at checkExpressionCached (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:61275:38)
at checkVariableLikeDeclaration (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:63983:69)
at checkVariableDeclaration (/home/m93a/Dokumenty/tsc-experiments/node_modules/typescript/lib/typescript.js:64051:20)
最佳答案
这可能是一种hacky方式,但既然你已经有了修改过的源代码,为什么不从中构建一个新的AST呢?例如:
const newSource = ts.createSourceFile(
'newSource.ts',
outputCode,
ts.ScriptTarget.ES5,
true
)
const newProgram = ts.createProgram(['newSource.ts'], { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS })
let emitResult = newProgram.emit()
这避免了对原始 AST 的更改并且运行时不会出错。
关于typescript - 如何在使用 Compiler API 进行类型检查之前转换 TypeScript 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63105982/
我正在寻找一种使此打印 HTML 代码 fragment 向后兼容旧 Android 版本的简单方法: @TargetApi(Build.VERSION_CODES.KITKAT) private v
我在 GCC 终端 (centos linux) 中为 ATM 项目编译以下 c 和 .h 代码时收到以下错误。请帮忙,因为我是编程新手。 validate_acc.h #ifndef _VALIDA
在写关于 SO 的不同问题的答案时,我制作了这个片段: @import url('https://fonts.googleapis.com/css?family=Shadows+Into+Light'
试图弄清楚我应该如何在 my_div_class 之前放置一个 span 而不是替换所有它。现在它取代了 div,但我不想这样做。我假设它类似于 :before 但不知道如何使用它。 { va
我正在使用选择库 http://github.hubspot.com/select/和 noUiSlider https://refreshless.com/nouislider/ .我面临的问题如下
我是开发新手,独自工作。我正在使用 Xcode 和 git 版本控制。可能我没有适本地组织和做错事,但我通常决定做 promise 只是为了在我破坏一切之前做出安全点。在那一刻,我发现很难恰本地描述我
我想确保在同一个桶和键上读取和写入时,应该更新获取的值,也就是说,应该在对其进行写入操作之后获取它。我怎样才能做到这一点? 我想要的是,如果我更新一个键的值,如果我同时使用不同线程获取值,则更新同一个
我的问题与this有关问题,已经有了答案: yes, there is a happens-before relationship imposed between actionsof the thre
The before and after hook documentation on Relish仅显示 before(:suite) 在 before(:all) 之前调用。 我什么时候应该使用其中
我有 CSV 行,我想在其中检测所有内部双引号,没有文本限定符。这几乎可以正常工作,但我的正则表达式还可以检测双引号后的字符。 CSV 部分: "7580";"Lorem ipsum";"";"Lor
是否可以通过Youtube数据API检查广告是否可以与特定视频一起显示? 我了解contentDetails.licensedContent仅显示视频是否已上传至同一伙伴然后由其声明版权。由于第三者权
考虑一下用漂亮的彩色图表描述的“像素管道” https://developers.google.com/web/fundamentals/performance/rendering/ 我有一个元素(比
之前?
在 MVC3 中,我可以轻松地将 jQuery 脚本标签移动到页面底部“_Layout.vbhtml” 但是,在 ASP.NET MVC3 中,当您使用编辑器模板创建 Controller 时,脚手
悬停时内容被替换,但是当鼠标离开元素时我希望它变回来。我该怎么做? $('.img-wrap').hover(function(){ $(this).find('h4').text('Go
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 已关闭 9 年前。 有关您编写的代码问题的问题必须在问题本身中描述具体问题 - 并包含有效代码以重现该问题。
版本:qwt 6.0.1我尝试开发频谱的对数缩放。我使用简单的线条来启用缩放plotspectrum->setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10S
我有两个相同的表,I_Subject 和 I_Temp_Subject,我想将 Temp_Subject 表复制到 Subject 表。 I_Temp_Subject 由简单用户使用,I_Subjec
我的印象是第一次绘制发生在触发 DOMContentLoaded 事件之后。特别是,因为我认为为了让第一次绘制发生,需要渲染树,它依赖于 DOM 构造。另外,我知道 DOM 构造完成时会触发 DOMC
我是一名优秀的程序员,十分优秀!