6

https://astexplorer.net/#/gist/70df1bc56b9ee73d19fc949d2ef829ed/7e14217fd8510f0bf83f3372bf08454b7617bce1

我现在发现我正在尝试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")
4

2 回答 2

2

这是一个执行您描述的变压器:

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()
}

在这里查看结果。

于 2018-05-03T19:45:54.670 回答
1

您可以使用我们的DMS 软件再造工具包来做到这一点。

DMS 将 HTML 页面视为带有嵌入式脚本子语言的原生 HTML 文本,可能是 ECMAScript、VBScript 或其他东西。因此,构建完整的 HTML“AST”的过程需要首先构建纯 HTML 部分,然后找到所有“onXXXXX”标签并将它们转换为所选脚本语言的 AST。DMS 可以将 AST 节点与不同的语言区分开来,因此在理解复合 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 文本片段,解析它们并将解析后的 ECMASCript 树拼接到其中以替换文本片段:

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

于 2018-05-03T22:33:10.827 回答