我为 Neo4j 构建了一个免费 Cypher 查询格式化器——原因与方法
Source: Dev.to

如果你已经使用 Neo4j 有一段时间了,你可能已经看到过一大段未格式化的 Cypher,类似下面这样:
MATCH (p:Person {name: 'Alice'})-[:FRIENDS_WITH]->(friend:Person)-[:WORKS_AT]->(c:Company) WHERE friend.age > 25 AND c.name STARTS WITH 'Neo' WITH p, friend, c, count(*) AS cnt ORDER BY cnt DESC LIMIT 10 OPTIONAL MATCH (friend)-[:LIVES_IN]->(city:City) WHERE city.population > 100000 RETURN p.name AS person, collect(DISTINCT friend.name) AS friends, c.name AS company, city.name AS city ORDER BY person ASC
并不容易阅读。我一直在从日志、Slack 消息以及 Stack Overflow 的答案中复制粘贴这种查询——手动重新格式化它们耗费了大量时间。所以我构建了一个工具来解决这个问题。
我构建的
Cypher Query Formatter — 一个免费、基于浏览器的工具,能够即时对凌乱的 Cypher 查询进行格式化,提供正确的缩进、换行和语法高亮。
上面的查询格式化后变为:
MATCH (p:Person {name: 'Alice'})-[:FRIENDS_WITH]->(friend:Person)-[:WORKS_AT]->(c:Company)
WHERE friend.age > 25
AND c.name STARTS WITH 'Neo'
WITH p, friend, c, count(*) AS cnt
ORDER BY cnt DESC
LIMIT 10
OPTIONAL MATCH (friend)-[:LIVES_IN]->(city:City)
WHERE city.population > 100000
RETURN p.name AS person,
collect(DISTINCT friend.name) AS friends,
c.name AS company,
city.name AS city
ORDER BY person ASC
好多了。
Features
- Instant formatting — paste your query, click Format (or hit
Ctrl+Enter). - Syntax highlighting — keywords, functions, labels, properties, strings and parameters all highlighted in distinct colors.
- Configurable indent — 2 spaces, 4 spaces, or tabs.
- Keyword case conversion — UPPERCASE, lowercase, or Capitalize.
- Dark and light theme.
- Copy to clipboard or download as
.cypherfile. - 100 % client‑side — your queries are never sent to any server.
Source: …
工作原理 — 技术细节
Tokenizer(分词器)
核心是一个手写的分词器,它逐字符遍历查询并输出带类型的 token(clause、sub_clause、function、string、number、comment、parameter、operator、bracket 等)。
难点在于正确处理 多词子句。Cypher 有诸如 OPTIONAL MATCH、ON CREATE SET、ORDER BY、STARTS WITH、IS NOT NULL 等结构。若采用朴素的逐词方式,会把 STARTS WITH 错误地拆分为操作符 STARTS 和主要子句 WITH。
解决方案是 在检查主要子句之前先匹配多词子句,使用最长匹配优先的已排序列表:
const MULTI_WORD_SUB_CLAUSES_SORTED = [
'IS NOT NULL',
'STARTS WITH',
'ENDS WITH',
'WITH HEADERS',
'IS NULL'
];
先检查这些项后,STARTS WITH 能被正确识别为子句操作符,而不会被误匹配为主要子句 WITH。
Formatter(格式化器)
在完成分词和分类后,格式化器重新构建查询字符串,具体规则如下:
- 在每个主要子句(
MATCH、WHERE、RETURN等)前插入换行。 - 在
WHERE块内部的AND、OR、XOR前插入缩进和换行。 - 在
RETURN、WITH、SET子句的逗号后插入缩进和换行。 - 在操作符和括号周围保持适当的空格。
Syntax Highlighter(语法高亮)
高亮器对已格式化的输出再次运行相同的分词器,并用带有 CSS 类的 <span> 包裹每种 token。上下文很重要——冒号 : 之后的标识符被视为标签(红色),点号 . 之后的标识符被视为属性(蓝色),否则视为变量(粉色)。
我学到的
- 从头编写分词器出乎意料地有趣。 边缘情况才是关键——字符串中的转义引号、反引号转义的标识符、块注释、以
$开头的参数。 - 多词关键字匹配需要仔细排序。 这在我刚开始时绊倒了我,导致格式化结果非常错误,直到我把顺序弄对为止。
- Cloudflare Pages 是托管此类静态工具的绝佳免费平台。 零配置、从 Git 即时部署、免费额度慷慨。
Try It
它是免费且向所有人开放的,并且可以在任何现代浏览器中使用。如果您遇到格式化不正确的查询,请在评论中告诉我。Cypher 中的边缘情况非常多,我确信我遗漏了一些。
使用原生 JavaScript 构建。没有框架、没有依赖、没有服务器。