如何用仅解析的JavaScript(String)替换AST中的路径



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的规则可以使用各种模式变量编写;请参阅上面的链接,并且可以在匹配的模式和其他状态信息上具有任意条件,以控制该规则是否适用。

最新更新