Skip to content

Commit 1d03d83

Browse files
Initial implementation
1 parent 38dacac commit 1d03d83

File tree

3 files changed

+241
-129
lines changed

3 files changed

+241
-129
lines changed

.gitignore

+2-129
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,3 @@
1-
# Logs
2-
logs
3-
*.log
4-
npm-debug.log*
5-
yarn-debug.log*
6-
yarn-error.log*
7-
lerna-debug.log*
8-
.pnpm-debug.log*
9-
10-
# Diagnostic reports (https://nodejs.org/api/report.html)
11-
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12-
13-
# Runtime data
14-
pids
15-
*.pid
16-
*.seed
17-
*.pid.lock
18-
19-
# Directory for instrumented libs generated by jscoverage/JSCover
20-
lib-cov
21-
22-
# Coverage directory used by tools like istanbul
23-
coverage
24-
*.lcov
25-
26-
# nyc test coverage
27-
.nyc_output
28-
29-
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30-
.grunt
31-
32-
# Bower dependency directory (https://bower.io/)
33-
bower_components
34-
35-
# node-waf configuration
36-
.lock-wscript
37-
38-
# Compiled binary addons (https://nodejs.org/api/addons.html)
39-
build/Release
40-
41-
# Dependency directories
421
node_modules/
43-
jspm_packages/
44-
45-
# Snowpack dependency directory (https://snowpack.dev/)
46-
web_modules/
47-
48-
# TypeScript cache
49-
*.tsbuildinfo
50-
51-
# Optional npm cache directory
52-
.npm
53-
54-
# Optional eslint cache
55-
.eslintcache
56-
57-
# Optional stylelint cache
58-
.stylelintcache
59-
60-
# Microbundle cache
61-
.rpt2_cache/
62-
.rts2_cache_cjs/
63-
.rts2_cache_es/
64-
.rts2_cache_umd/
65-
66-
# Optional REPL history
67-
.node_repl_history
68-
69-
# Output of 'npm pack'
70-
*.tgz
71-
72-
# Yarn Integrity file
73-
.yarn-integrity
74-
75-
# dotenv environment variable files
76-
.env
77-
.env.development.local
78-
.env.test.local
79-
.env.production.local
80-
.env.local
81-
82-
# parcel-bundler cache (https://parceljs.org/)
83-
.cache
84-
.parcel-cache
85-
86-
# Next.js build output
87-
.next
88-
out
89-
90-
# Nuxt.js build / generate output
91-
.nuxt
92-
dist
93-
94-
# Gatsby files
95-
.cache/
96-
# Comment in the public line in if your project uses Gatsby and not Next.js
97-
# https://nextjs.org/blog/next-9-1#public-directory-support
98-
# public
99-
100-
# vuepress build output
101-
.vuepress/dist
102-
103-
# vuepress v2.x temp and cache directory
104-
.temp
105-
.cache
106-
107-
# Docusaurus cache and generated files
108-
.docusaurus
109-
110-
# Serverless directories
111-
.serverless/
112-
113-
# FuseBox cache
114-
.fusebox/
115-
116-
# DynamoDB Local files
117-
.dynamodb/
118-
119-
# TernJS port file
120-
.tern-port
121-
122-
# Stores VSCode versions used for testing VSCode extensions
123-
.vscode-test
124-
125-
# yarn v2
126-
.yarn/cache
127-
.yarn/unplugged
128-
.yarn/build-state.yml
129-
.yarn/install-state.gz
130-
.pnp.*
2+
.idea
3+
./run.sh

index.js

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
// Declare global variables to avoid warnings in JSHint
2+
/* global CodeMirror, define */
3+
4+
(function (mod) {
5+
if (typeof exports === "object" && typeof module === "object") // CommonJS
6+
mod(require("codemirror/lib/codemirror"));
7+
else if (typeof define === "function" && define.amd) // AMD
8+
define(["codemirror/lib/codemirror"], mod);
9+
else // Plain browser env
10+
mod(CodeMirror);
11+
})(function (CodeMirror) {
12+
"use strict";
13+
14+
CodeMirror.defineMode("aql", function(config) {
15+
var indentUnit = config.indentUnit;
16+
var curPunc;
17+
18+
// ops and keywords taken from ArangoDB UI code:
19+
// https://github.com/arangodb/arangodb/blob/devel/js/apps/system/_admin/aardvark/APP/react/public/assets/src/mode-aql.js
20+
function wordRegexp(words) {
21+
return new RegExp("^(?:" + words + ")$", "i");
22+
}
23+
var ops = wordRegexp(
24+
"to_bool|to_number|to_string|to_array|to_list|is_null|is_bool|is_number|is_string|is_array|is_list|is_object|is_document|is_datestring|" +
25+
"typename|json_stringify|json_parse|concat|concat_separator|char_length|lower|upper|substring|left|right|trim|reverse|contains|" +
26+
"log|log2|log10|exp|exp2|sin|cos|tan|asin|acos|atan|atan2|radians|degrees|pi|regex_test|regex_replace|" +
27+
"like|floor|ceil|round|abs|rand|sqrt|pow|length|count|min|max|average|avg|sum|product|median|variance_population|variance_sample|variance|" +
28+
"bit_and|bit_or|bit_xor|bit_negate|bit_test|bit_popcount|bit_shift_left|bit_shift_right|bit_construct|bit_deconstruct|bit_to_string|bit_from_string|" +
29+
"first|last|unique|outersection|interleave|in_range|jaccard|matches|merge|merge_recursive|has|attributes|values|unset|unset_recursive|keep|" +
30+
"near|within|within_rectangle|is_in_polygon|distance|fulltext|stddev_sample|stddev_population|stddev|" +
31+
"slice|nth|position|contains_array|translate|zip|call|apply|push|append|pop|shift|unshift|remove_value|remove_values|" +
32+
"remove_nth|replace_nth|date_now|date_timestamp|date_iso8601|date_dayofweek|date_year|date_month|date_day|date_hour|" +
33+
"date_minute|date_second|date_millisecond|date_dayofyear|date_isoweek|date_leapyear|date_quarter|date_days_in_month|date_trunc|date_round|" +
34+
"date_add|date_subtract|date_diff|date_compare|date_format|date_utctolocal|date_localtoutc|date_timezone|date_timezones|" +
35+
"fail|passthru|v8|sleep|schema_get|schema_validate|call_greenspun|version|noopt|noeval|not_null|" +
36+
"first_list|first_document|parse_identifier|current_user|current_database|collection_count|pregel_result|" +
37+
"collections|document|decode_rev|range|union|union_distinct|minus|intersection|flatten|is_same_collection|check_document|" +
38+
"ltrim|rtrim|find_first|find_last|split|substitute|ipv4_to_number|ipv4_from_number|is_ipv4|md5|sha1|sha512|crc32|fnv64|hash|random_token|to_base64|" +
39+
"to_hex|encode_uri_component|soundex|assert|warn|is_key|sorted|sorted_unique|count_distinct|count_unique|" +
40+
"levenshtein_distance|levenshtein_match|regex_matches|regex_split|ngram_match|ngram_similarity|ngram_positional_similarity|uuid|" +
41+
"tokens|exists|starts_with|phrase|min_match|boost|analyzer|" +
42+
"geo_point|geo_multipoint|geo_polygon|geo_multipolygon|geo_linestring|geo_multilinestring|geo_contains|geo_intersects|" +
43+
"geo_equals|geo_distance|geo_area|geo_in_range"
44+
);
45+
46+
var keywords = wordRegexp(
47+
"for|return|filter|search|sort|limit|let|collect|asc|desc|in|into|insert|update|remove|replace|upsert|options|with|and|or|not|distinct|graph|shortest_path|outbound|inbound|any|all|none|aggregate|like|k_shortest_paths|k_paths|prune|window" +
48+
"|" +
49+
"search|keep|to|prune|options"
50+
);
51+
var operatorChars = /[*+\-<>=&|\^\/!\?]/;
52+
var PN_CHARS = "[A-Za-z_\\-0-9]";
53+
var PREFIX_START = new RegExp("[A-Za-z]");
54+
var PREFIX_REMAINDER = new RegExp("((" + PN_CHARS + "|\\.)*(" + PN_CHARS + "))?:");
55+
56+
function tokenComment(stream, state) {
57+
var maybeEnd = false, ch;
58+
while (ch = stream.next()) {
59+
if (ch == "/" && maybeEnd) {
60+
state.tokenize = null;
61+
break;
62+
}
63+
maybeEnd = (ch == "*");
64+
}
65+
return "comment";
66+
}
67+
68+
function tokenBase(stream, state) {
69+
var ch = stream.next();
70+
curPunc = null;
71+
if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
72+
stream.match(/^[^\s\u00a0>]*>?/);
73+
return "atom";
74+
}
75+
else if (ch == "\"" || ch == "'" || ch == "`" || ch == "´") {
76+
state.tokenize = tokenLiteral(ch);
77+
return state.tokenize(stream, state);
78+
}
79+
else if (/[{}\(\),\.;\[\]]/.test(ch)) {
80+
curPunc = ch;
81+
return "bracket";
82+
}
83+
else if (ch == "/") {
84+
if (stream.eat("*")) {
85+
state.tokenize = tokenComment;
86+
return state.tokenize(stream, state);
87+
}
88+
if (stream.eat("/")) {
89+
stream.skipToEnd();
90+
return "comment";
91+
}
92+
}
93+
else if (operatorChars.test(ch)) {
94+
return "operator";
95+
}
96+
else if (ch == ":") {
97+
eatPnLocal(stream);
98+
return "atom";
99+
}
100+
else if (ch == "@") {
101+
stream.eatWhile(/[a-z\d\-]/i);
102+
return "meta";
103+
}
104+
else if (PREFIX_START.test(ch) && stream.match(PREFIX_REMAINDER)) {
105+
eatPnLocal(stream);
106+
return "atom";
107+
}
108+
stream.eatWhile(/[_\w\d]/);
109+
var word = stream.current();
110+
if (ops.test(word))
111+
return "builtin";
112+
else if (keywords.test(word))
113+
return "keyword";
114+
else
115+
return "variable";
116+
}
117+
118+
function eatPnLocal(stream) {
119+
stream.match(/(\.(?=[\w_\-\\%])|[:\w_-]|\\[-\\_~.!$&'()*+,;=/?#@%]|%[a-f\d][a-f\d])+/i);
120+
}
121+
122+
function tokenLiteral(quote) {
123+
return function(stream, state) {
124+
var escaped = false, ch;
125+
while ((ch = stream.next()) != null) {
126+
if (ch == quote && !escaped) {
127+
state.tokenize = tokenBase;
128+
break;
129+
}
130+
escaped = !escaped && ch == "\\";
131+
}
132+
return "string";
133+
};
134+
}
135+
136+
function pushContext(state, type, col) {
137+
state.context = {prev: state.context, indent: state.indent, col: col, type: type};
138+
}
139+
function popContext(state) {
140+
state.indent = state.context.indent;
141+
state.context = state.context.prev;
142+
}
143+
144+
return {
145+
startState: function() {
146+
return {tokenize: tokenBase,
147+
context: null,
148+
indent: 0,
149+
col: 0};
150+
},
151+
152+
token: function(stream, state) {
153+
if (stream.sol()) {
154+
if (state.context && state.context.align == null) state.context.align = false;
155+
state.indent = stream.indentation();
156+
}
157+
if (stream.eatSpace()) return null;
158+
var style = (state.tokenize || tokenBase)(stream, state);
159+
160+
if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") {
161+
state.context.align = true;
162+
}
163+
164+
if (curPunc == "(") pushContext(state, ")", stream.column());
165+
else if (curPunc == "[") pushContext(state, "]", stream.column());
166+
else if (curPunc == "{") pushContext(state, "}", stream.column());
167+
else if (/[\]\}\)]/.test(curPunc)) {
168+
while (state.context && state.context.type == "pattern") popContext(state);
169+
if (state.context && curPunc == state.context.type) {
170+
popContext(state);
171+
if (curPunc == "}" && state.context && state.context.type == "pattern")
172+
popContext(state);
173+
}
174+
}
175+
else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state);
176+
else if (/atom|string|variable/.test(style) && state.context) {
177+
if (/[\}\]]/.test(state.context.type))
178+
pushContext(state, "pattern", stream.column());
179+
else if (state.context.type == "pattern" && !state.context.align) {
180+
state.context.align = true;
181+
state.context.col = stream.column();
182+
}
183+
}
184+
185+
return style;
186+
},
187+
188+
indent: function(state, textAfter) {
189+
var firstChar = textAfter && textAfter.charAt(0);
190+
var context = state.context;
191+
if (/[\]\}]/.test(firstChar))
192+
while (context && context.type == "pattern") context = context.prev;
193+
194+
var closing = context && firstChar == context.type;
195+
if (!context)
196+
return 0;
197+
else if (context.type == "pattern")
198+
return context.col;
199+
else if (context.align)
200+
return context.col + (closing ? 0 : 1);
201+
else
202+
return context.indent + (closing ? 0 : indentUnit);
203+
},
204+
205+
blockCommentStart: "/*",
206+
blockCommentEnd: "*/",
207+
lineComment: "//"
208+
};
209+
});
210+
211+
CodeMirror.defineMIME("text/x-aql", "aql");
212+
213+
214+
});

package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "cm5-aql",
3+
"version": "1.0.0",
4+
"description": "A CodeMirror mode for ArangoDB Query Language (AQL)",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "true"
8+
},
9+
"keywords": [
10+
"codemirror5",
11+
"codemirror-mode",
12+
"arangodb",
13+
"aql",
14+
"arangodb-ql"
15+
],
16+
"author": "Nikita Vaniasin",
17+
"repository": {
18+
"url": "git@github.com:nikita-vanyasin/cm5-aql.git",
19+
"type": "git"
20+
},
21+
"bugs": {
22+
"url": "https://github.com/nikita-vanyasin/cm5-aql/issues"
23+
},
24+
"license": "MIT"
25+
}

0 commit comments

Comments
 (0)