cypher.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. // By the Neo4j Team and contributors.
  4. // https://github.com/neo4j-contrib/CodeMirror
  5. ;(function (mod) {
  6. if (typeof exports == 'object' && typeof module == 'object')
  7. // CommonJS
  8. mod(require('../../lib/codemirror'))
  9. else if (typeof define == 'function' && define.amd)
  10. // AMD
  11. define(['../../lib/codemirror'], mod)
  12. // Plain browser env
  13. else mod(CodeMirror)
  14. })(function (CodeMirror) {
  15. 'use strict'
  16. var wordRegexp = function (words) {
  17. return new RegExp('^(?:' + words.join('|') + ')$', 'i')
  18. }
  19. CodeMirror.defineMode('cypher', function (config) {
  20. var tokenBase = function (stream /*, state*/) {
  21. curPunc = null
  22. var ch = stream.next()
  23. if (ch === '"') {
  24. stream.match(/^[^"]*"/)
  25. return 'string'
  26. }
  27. if (ch === "'") {
  28. stream.match(/^[^']*'/)
  29. return 'string'
  30. }
  31. if (/[{}\(\),\.;\[\]]/.test(ch)) {
  32. curPunc = ch
  33. return 'node'
  34. } else if (ch === '/' && stream.eat('/')) {
  35. stream.skipToEnd()
  36. return 'comment'
  37. } else if (operatorChars.test(ch)) {
  38. stream.eatWhile(operatorChars)
  39. return null
  40. } else {
  41. stream.eatWhile(/[_\w\d]/)
  42. if (stream.eat(':')) {
  43. stream.eatWhile(/[\w\d_\-]/)
  44. return 'atom'
  45. }
  46. var word = stream.current()
  47. if (funcs.test(word)) return 'builtin'
  48. if (preds.test(word)) return 'def'
  49. if (keywords.test(word) || systemKeywords.test(word)) return 'keyword'
  50. return 'variable'
  51. }
  52. }
  53. var pushContext = function (state, type, col) {
  54. return (state.context = {
  55. prev: state.context,
  56. indent: state.indent,
  57. col: col,
  58. type: type,
  59. })
  60. }
  61. var popContext = function (state) {
  62. state.indent = state.context.indent
  63. return (state.context = state.context.prev)
  64. }
  65. var indentUnit = config.indentUnit
  66. var curPunc
  67. var funcs = wordRegexp([
  68. 'abs',
  69. 'acos',
  70. 'allShortestPaths',
  71. 'asin',
  72. 'atan',
  73. 'atan2',
  74. 'avg',
  75. 'ceil',
  76. 'coalesce',
  77. 'collect',
  78. 'cos',
  79. 'cot',
  80. 'count',
  81. 'degrees',
  82. 'e',
  83. 'endnode',
  84. 'exp',
  85. 'extract',
  86. 'filter',
  87. 'floor',
  88. 'haversin',
  89. 'head',
  90. 'id',
  91. 'keys',
  92. 'labels',
  93. 'last',
  94. 'left',
  95. 'length',
  96. 'log',
  97. 'log10',
  98. 'lower',
  99. 'ltrim',
  100. 'max',
  101. 'min',
  102. 'node',
  103. 'nodes',
  104. 'percentileCont',
  105. 'percentileDisc',
  106. 'pi',
  107. 'radians',
  108. 'rand',
  109. 'range',
  110. 'reduce',
  111. 'rel',
  112. 'relationship',
  113. 'relationships',
  114. 'replace',
  115. 'reverse',
  116. 'right',
  117. 'round',
  118. 'rtrim',
  119. 'shortestPath',
  120. 'sign',
  121. 'sin',
  122. 'size',
  123. 'split',
  124. 'sqrt',
  125. 'startnode',
  126. 'stdev',
  127. 'stdevp',
  128. 'str',
  129. 'substring',
  130. 'sum',
  131. 'tail',
  132. 'tan',
  133. 'timestamp',
  134. 'toFloat',
  135. 'toInt',
  136. 'toString',
  137. 'trim',
  138. 'type',
  139. 'upper',
  140. ])
  141. var preds = wordRegexp(['all', 'and', 'any', 'contains', 'exists', 'has', 'in', 'none', 'not', 'or', 'single', 'xor'])
  142. var keywords = wordRegexp([
  143. 'as',
  144. 'asc',
  145. 'ascending',
  146. 'assert',
  147. 'by',
  148. 'case',
  149. 'commit',
  150. 'constraint',
  151. 'create',
  152. 'csv',
  153. 'cypher',
  154. 'delete',
  155. 'desc',
  156. 'descending',
  157. 'detach',
  158. 'distinct',
  159. 'drop',
  160. 'else',
  161. 'end',
  162. 'ends',
  163. 'explain',
  164. 'false',
  165. 'fieldterminator',
  166. 'foreach',
  167. 'from',
  168. 'headers',
  169. 'in',
  170. 'index',
  171. 'is',
  172. 'join',
  173. 'limit',
  174. 'load',
  175. 'match',
  176. 'merge',
  177. 'null',
  178. 'on',
  179. 'optional',
  180. 'order',
  181. 'periodic',
  182. 'profile',
  183. 'remove',
  184. 'return',
  185. 'scan',
  186. 'set',
  187. 'skip',
  188. 'start',
  189. 'starts',
  190. 'then',
  191. 'true',
  192. 'union',
  193. 'unique',
  194. 'unwind',
  195. 'using',
  196. 'when',
  197. 'where',
  198. 'with',
  199. 'call',
  200. 'yield',
  201. ])
  202. var systemKeywords = wordRegexp([
  203. 'access',
  204. 'active',
  205. 'assign',
  206. 'all',
  207. 'alter',
  208. 'as',
  209. 'catalog',
  210. 'change',
  211. 'copy',
  212. 'create',
  213. 'constraint',
  214. 'constraints',
  215. 'current',
  216. 'database',
  217. 'databases',
  218. 'dbms',
  219. 'default',
  220. 'deny',
  221. 'drop',
  222. 'element',
  223. 'elements',
  224. 'exists',
  225. 'from',
  226. 'grant',
  227. 'graph',
  228. 'graphs',
  229. 'if',
  230. 'index',
  231. 'indexes',
  232. 'label',
  233. 'labels',
  234. 'management',
  235. 'match',
  236. 'name',
  237. 'names',
  238. 'new',
  239. 'node',
  240. 'nodes',
  241. 'not',
  242. 'of',
  243. 'on',
  244. 'or',
  245. 'password',
  246. 'populated',
  247. 'privileges',
  248. 'property',
  249. 'read',
  250. 'relationship',
  251. 'relationships',
  252. 'remove',
  253. 'replace',
  254. 'required',
  255. 'revoke',
  256. 'role',
  257. 'roles',
  258. 'set',
  259. 'show',
  260. 'start',
  261. 'status',
  262. 'stop',
  263. 'suspended',
  264. 'to',
  265. 'traverse',
  266. 'type',
  267. 'types',
  268. 'user',
  269. 'users',
  270. 'with',
  271. 'write',
  272. ])
  273. var operatorChars = /[*+\-<>=&|~%^]/
  274. return {
  275. startState: function (/*base*/) {
  276. return {
  277. tokenize: tokenBase,
  278. context: null,
  279. indent: 0,
  280. col: 0,
  281. }
  282. },
  283. token: function (stream, state) {
  284. if (stream.sol()) {
  285. if (state.context && state.context.align == null) {
  286. state.context.align = false
  287. }
  288. state.indent = stream.indentation()
  289. }
  290. if (stream.eatSpace()) {
  291. return null
  292. }
  293. var style = state.tokenize(stream, state)
  294. if (style !== 'comment' && state.context && state.context.align == null && state.context.type !== 'pattern') {
  295. state.context.align = true
  296. }
  297. if (curPunc === '(') {
  298. pushContext(state, ')', stream.column())
  299. } else if (curPunc === '[') {
  300. pushContext(state, ']', stream.column())
  301. } else if (curPunc === '{') {
  302. pushContext(state, '}', stream.column())
  303. } else if (/[\]\}\)]/.test(curPunc)) {
  304. while (state.context && state.context.type === 'pattern') {
  305. popContext(state)
  306. }
  307. if (state.context && curPunc === state.context.type) {
  308. popContext(state)
  309. }
  310. } else if (curPunc === '.' && state.context && state.context.type === 'pattern') {
  311. popContext(state)
  312. } else if (/atom|string|variable/.test(style) && state.context) {
  313. if (/[\}\]]/.test(state.context.type)) {
  314. pushContext(state, 'pattern', stream.column())
  315. } else if (state.context.type === 'pattern' && !state.context.align) {
  316. state.context.align = true
  317. state.context.col = stream.column()
  318. }
  319. }
  320. return style
  321. },
  322. indent: function (state, textAfter) {
  323. var firstChar = textAfter && textAfter.charAt(0)
  324. var context = state.context
  325. if (/[\]\}]/.test(firstChar)) {
  326. while (context && context.type === 'pattern') {
  327. context = context.prev
  328. }
  329. }
  330. var closing = context && firstChar === context.type
  331. if (!context) return 0
  332. if (context.type === 'keywords') return CodeMirror.commands.newlineAndIndent
  333. if (context.align) return context.col + (closing ? 0 : 1)
  334. return context.indent + (closing ? 0 : indentUnit)
  335. },
  336. }
  337. })
  338. CodeMirror.modeExtensions['cypher'] = {
  339. autoFormatLineBreaks: function (text) {
  340. var i, lines, reProcessedPortion
  341. var lines = text.split('\n')
  342. var reProcessedPortion = /\s+\b(return|where|order by|match|with|skip|limit|create|delete|set)\b\s/g
  343. for (var i = 0; i < lines.length; i++) lines[i] = lines[i].replace(reProcessedPortion, ' \n$1 ').trim()
  344. return lines.join('\n')
  345. },
  346. }
  347. CodeMirror.defineMIME('application/x-cypher-query', 'cypher')
  348. })