https://astexplorer.net/#/gist/70df1bc56b9ee73d19fc949d29ed/7E14217E14217FD855117FD8510F8510F83F83F83F83F3372BF3372BF08454BCE1 <<p>我现在发现我正在尝试 replace
表达式,但我不在乎其中的内容。
在此示例中,我在
中找到了this.state.showMenu && this.handleMouseDown
部分 <a
onMouseDown={this.state.showMenu && this.handleMouseDown}
>
我需要转换为:
<a
onMouseDown={this.state.showMenu ? this.handleMouseDown : undefined}
>
如果不明确重建树,我该怎么做?我只想做
之类的事情path.replaceText("this.state.showMenu ? this.handleMouseDown : undefined")
这是一个变压器,可以执行您描述的内容:
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source)
root
.find(j.JSXExpressionContainer)
.replaceWith(path => {
return j.jsxExpressionContainer(
j.conditionalExpression(
j.identifier(j(path.value.expression.left).toSource()),
j.identifier(j(path.value.expression.right).toSource()),
j.identifier('undefined')
)
)
})
return root.toSource()
}
在这里看到它。
您也可以将任意文本放在JSXExpressionContainer
节点中:
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source)
root
.find(j.JSXExpressionContainer)
.replaceWith(path => {
return j.jsxExpressionContainer(
j.identifier('whatever you want')
)
})
return root.toSource()
}
请参阅此示例。
最后,您甚至不需要返回JSXExpressionContainer
。
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source)
root
.find(j.JSXExpressionContainer)
.replaceWith(path => {
return j.identifier("this isn't valid JS, but works just fine")
})
return root.toSource()
}
请参阅此处的结果。
您可以使用我们的DMS软件重新设计工具包进行此操作。
dms将HTML页面视为本机HTML文本,并带有嵌入式脚本sublanguage(可能是ecmascript,vbScript或其他内容(。因此,构建完整的HTML" AST"的过程需要首先构建纯HTML零件,然后找到所有" onxxxxx"标签,然后以所选的脚本语言将其转换为AST。DMS可以将AST节点与不同的langauges区分开,因此没有机会理解化合物AST。
因此,首先我们需要解析HTML感兴趣的文档(出于教学原因编辑的代码(:
(local (;; [my_HTML_AST AST:Node]
(includeunique `DMS/Domains/HTML/Component/ParserComponent.par')
);;
(= working_graph (AST:CreateForest))
(= my_HTML_AST (Parser:ParseFile parser working_graph input_file_full_path))
然后,我们需要在HTML树上行走,找到JavaScript文本片段,解析它们并剪接解析的Ecmasiprcript树以替换文本片段:
(local (;; (includeunique `DMS/Domains/ECMAScript/Components/ParserComponent.par') );;
(ScanNodes my_HTML_AST
(lambda (function boolean AST:Node)
(ifthenelse (!! (~= (AST:GetNodeType ?) GrammarConstants:Rule:Attribute) ; not an HTML attribute
(~= (Strings:Prefix (AST:GetLiteralString (AST:GetFirstChild ?)) `on')) ; not at action attribute
)&&
~t ; scan deeper into tree
(value (local (;; [my_ECMAScript_AST AST:Node]
[ECMASCript_text_stream streams:buffer]
);;
(= ECMAScript_text_stream (InputStream:MakeBufferStream (AST:StringLiteral (AST:GetSecondChild ?))=
(= my_ECMAScript_AST (Parser:ParseStream parser working_graph ECMAScript_text_stream))
(= AST:ReplaceNode ? my_ECMAScript_AST)
(= InputStream:Close my_ECMAScript_text_stream)
~f) ; no need to scan deeper here
)ifthenelse
)lambda
) ; at this point, we have a mixed HTML/ECMAScript tree
)local
如果脚本语言可能是其他的,则此代码必须更改。如果您的页面都是HTML ECMAScript,则可以将上述内容包装到黑匣子中,并将其称为"(Parsehtml(",这是另一个答案的发生。
现在进行实际工作。OP希望用另一个在他的HTML中发现的图案。在这里,DMS发光是因为您可以使用目标语言的语法来编写这些模式,直接作为DMS重写规则(有关详细信息,请参见此链接(。
source domain ECMAScript;
target domain ECMAScript;
rule OP_special_rewrite()=expression -> expression
"this.state.showMenu && this.handleMouseDown"
-> "this.state.showMenu ? this.handleMouseDown : undefined "
现在您需要应用此重写:
(RSL:Apply my_HTML_AST `OP_special_rewrite') ; applies this rule to every node in AST
; only those that match get modified
最终从AST重新生成文本:
(PrettyPrinter:PrintStream my_ECMAScript_AST input_file_full_path)
op的示例很简单,仅仅是因为他与恒定模式相匹配。DMS的规则可以使用各种模式变量编写;请参阅上面的链接,并且可以在匹配的模式和其他状态信息上具有任意条件,以控制该规则是否适用。