Json 如何使用Aeson生成文字(无引号)javascript表达式?

Json 如何使用Aeson生成文字(无引号)javascript表达式?,json,haskell,object-literal,aeson,template-haskell,Json,Haskell,Object Literal,Aeson,Template Haskell,我正在使用并且需要通过Aeson: {logLevel:vega.Debug} 这应该是指绑定不导出的javascript包中的 afaict我应该使用Data.Aeson.QQ.Simple来实现这一点,但我尝试编译的所有东西都会在“vega.Debug”周围加上引号,这是我无法做到的 [aesonQQ{logLevel:“vega.Debug”}} 我错过了什么?有没有办法做到这一点?一般来说,AesonValues只表示JSON对象,因此它们不支持嵌入式JavaScript表达式或任何

我正在使用并且需要通过Aeson:


{logLevel:vega.Debug}
这应该是指绑定不导出的javascript包中的

afaict我应该使用
Data.Aeson.QQ.Simple
来实现这一点,但我尝试编译的所有东西都会在
“vega.Debug”
周围加上引号,这是我无法做到的

[aesonQQ{logLevel:“vega.Debug”}}

我错过了什么?有没有办法做到这一点?

一般来说,Aeson
Value
s只表示JSON对象,因此它们不支持嵌入式JavaScript表达式或任何其他扩展

如果这个API只接受
s,那么您就卡住了。我认为最好的解决方案是复制vega.Debug的整数值并序列化

否则,一个简单的解决方案是制作一个修改版本的
toHtmlWith
,该版本接受更灵活的输入类型,例如字符串:

toHtmlWith' :: Maybe Text -> VegaLite -> Text
toHtmlWith' mopts vl =
  let spec = encodeToLazyText (fromVL vl)
      -- NB: Removed ‘encodeToLazyText’ call here.
      opts = maybe "" (\o -> "," <> o) mopts

  in TL.unlines
    [ "<!DOCTYPE html>"
    , "<html>"
    , "<head>"
      -- versions are fixed at vega 5, vega-lite 4
    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega@5\"></script>"
    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega-lite@4\"></script>"
    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega-embed\"></script>"
    , "</head>"
    , "<body>"
    , "<div id=\"vis\"></div>"
    , "<script type=\"text/javascript\">"
    , "  var spec = " <> spec <> ";"
    , "  vegaEmbed(\'#vis\', spec" <> opts <> ").then(function(result) {"
    , "  // Access the Vega view instance (https://vega.github.io/vega/docs/api/view/) as result.view"
    , "  }).catch(console.error);"
    , "</script>"
    , "</body>"
    , "</html>"
    ]
有没有一种方法可以使用编码

作为另一种攻击,您可以为您的类型创建一个
ToJSON
实例,该实例实现
toEncoding
,但不实现
ToJSON
,并将编码值设置为JavaScript表达式(即无效JSON)。您可能希望使
toJSON
引发一个错误,这样您就不会无意中使用它


如果您想生成JavaScript代码,我将看一看。不要生成
,而是生成一个值,然后使用一个漂亮的打印函数来渲染它。下面是一个可能解决方案的结构示意图:

-- Like ‘ToJSON’ but may produce arbitrary JavaScript expressions
class ToJavaScript a where
  toJavaScript :: a -> JSExpression

-- Helper function to convert from Aeson Value
jsFromJson :: Value -> JSExpression
jsFromJson v = case v of
  Object o -> JSObjectLiteral …
  Array a -> JSArrayLiteral …
  String s -> JSStringLiteral …
  …

instance ToJavaScript YourType where
  toJavaScript = …

rendered :: Text
rendered = renderToText
  $ JSAstExpression (toJavaScript yourValue) JSNoAnnot
您的表达式的形式如下:

JSMemberDot
  (JSIdentifier JSNoAnnot "vega")
  JSNoAnnot
  (JSIdentifier JSNoAnnot "Debug")

JSAnnot
类型还允许您在生成的结果中包含注释。请记住,
语言javascript
漂亮的打印可能不如Aeson的JSON序列化优化。

{logLevel:vega.Debug}
不是有效的JSON,因此不能将其作为Aeson
值编写。你能澄清一下你到底想说什么吗?@Sir4ur0n-oh真的吗?呵呵!我觉得javascript非常讨厌,所以我尽量少碰它,所以我几乎不知道它或JSON。我正在尝试设置
logLevel
选项,如上所述。它指的是类型
级别
,它指的是在操作链接的枚举中定义的值,如
vega.Debug
。如果我使用裸Int,它会工作:
toJSON-VOpt{logLevel=2}
where
VOpt
只需新键入一个Int,然后实例
toJSON
。JSON不允许您将表达式作为字段值吗?如果没有,为什么?如果绑定没有公开这些常量,您可以在Haskell程序中手动定义它们,例如
Debug::Int
Debug=1
,然后使用
{logLevel:Debug}
。这对你的用例有用吗?我的意思当然是
{logLevel=Debug}
。@ArtemPelenitsyn-听起来像我的
VOpt
黑客,我正在试图找出如何做到“正确”——即安全、干净、无重复:)谢谢你的超级彻底的回答!
toEncoding
的想法看起来很小很干净,你有什么理由轻视它吗?:)@user1441998:我不知道它是否会起作用,主要是因为我不知道是否有案例应该首先通过
toJSON
进行编码。它也打破了我所期望的
ToJSON
的不变量,即通过
toencode
encode进行编码。toJSON
应该产生相同的最终结果。
JSMemberDot
  (JSIdentifier JSNoAnnot "vega")
  JSNoAnnot
  (JSIdentifier JSNoAnnot "Debug")