You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
699 lines
12 KiB
699 lines
12 KiB
/** |
|
* @param {string} value |
|
* @returns {RegExp} |
|
* */ |
|
|
|
/** |
|
* @param {RegExp | string } re |
|
* @returns {string} |
|
*/ |
|
function source(re) { |
|
if (!re) return null; |
|
if (typeof re === "string") return re; |
|
|
|
return re.source; |
|
} |
|
|
|
/** |
|
* @param {...(RegExp | string) } args |
|
* @returns {string} |
|
*/ |
|
function concat(...args) { |
|
const joined = args.map((x) => source(x)).join(""); |
|
return joined; |
|
} |
|
|
|
/** |
|
* Any of the passed expresssions may match |
|
* |
|
* Creates a huge this | this | that | that match |
|
* @param {(RegExp | string)[] } args |
|
* @returns {string} |
|
*/ |
|
function either(...args) { |
|
const joined = '(' + args.map((x) => source(x)).join("|") + ")"; |
|
return joined; |
|
} |
|
|
|
/* |
|
Language: SQL |
|
Website: https://en.wikipedia.org/wiki/SQL |
|
Category: common, database |
|
*/ |
|
|
|
function sql(hljs) { |
|
const COMMENT_MODE = hljs.COMMENT('--', '$'); |
|
const STRING = { |
|
className: 'string', |
|
variants: [ |
|
{ |
|
begin: /'/, |
|
end: /'/, |
|
contains: [ |
|
{begin: /''/ } |
|
] |
|
} |
|
] |
|
}; |
|
const QUOTED_IDENTIFIER = { |
|
begin: /"/, |
|
end: /"/, |
|
contains: [ { begin: /""/ } ] |
|
}; |
|
|
|
const LITERALS = [ |
|
"true", |
|
"false", |
|
// Not sure it's correct to call NULL literal, and clauses like IS [NOT] NULL look strange that way. |
|
// "null", |
|
"unknown" |
|
]; |
|
|
|
const MULTI_WORD_TYPES = [ |
|
"double precision", |
|
"large object", |
|
"with timezone", |
|
"without timezone" |
|
]; |
|
|
|
const TYPES = [ |
|
'bigint', |
|
'binary', |
|
'blob', |
|
'boolean', |
|
'char', |
|
'character', |
|
'clob', |
|
'date', |
|
'dec', |
|
'decfloat', |
|
'decimal', |
|
'float', |
|
'int', |
|
'integer', |
|
'interval', |
|
'nchar', |
|
'nclob', |
|
'national', |
|
'numeric', |
|
'real', |
|
'row', |
|
'smallint', |
|
'time', |
|
'timestamp', |
|
'varchar', |
|
'varying', // modifier (character varying) |
|
'varbinary' |
|
]; |
|
|
|
const NON_RESERVED_WORDS = [ |
|
"add", |
|
"asc", |
|
"collation", |
|
"desc", |
|
"final", |
|
"first", |
|
"last", |
|
"view" |
|
]; |
|
|
|
// https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#reserved-word |
|
const RESERVED_WORDS = [ |
|
"abs", |
|
"acos", |
|
"all", |
|
"allocate", |
|
"alter", |
|
"and", |
|
"any", |
|
"are", |
|
"array", |
|
"array_agg", |
|
"array_max_cardinality", |
|
"as", |
|
"asensitive", |
|
"asin", |
|
"asymmetric", |
|
"at", |
|
"atan", |
|
"atomic", |
|
"authorization", |
|
"avg", |
|
"begin", |
|
"begin_frame", |
|
"begin_partition", |
|
"between", |
|
"bigint", |
|
"binary", |
|
"blob", |
|
"boolean", |
|
"both", |
|
"by", |
|
"call", |
|
"called", |
|
"cardinality", |
|
"cascaded", |
|
"case", |
|
"cast", |
|
"ceil", |
|
"ceiling", |
|
"char", |
|
"char_length", |
|
"character", |
|
"character_length", |
|
"check", |
|
"classifier", |
|
"clob", |
|
"close", |
|
"coalesce", |
|
"collate", |
|
"collect", |
|
"column", |
|
"commit", |
|
"condition", |
|
"connect", |
|
"constraint", |
|
"contains", |
|
"convert", |
|
"copy", |
|
"corr", |
|
"corresponding", |
|
"cos", |
|
"cosh", |
|
"count", |
|
"covar_pop", |
|
"covar_samp", |
|
"create", |
|
"cross", |
|
"cube", |
|
"cume_dist", |
|
"current", |
|
"current_catalog", |
|
"current_date", |
|
"current_default_transform_group", |
|
"current_path", |
|
"current_role", |
|
"current_row", |
|
"current_schema", |
|
"current_time", |
|
"current_timestamp", |
|
"current_path", |
|
"current_role", |
|
"current_transform_group_for_type", |
|
"current_user", |
|
"cursor", |
|
"cycle", |
|
"date", |
|
"day", |
|
"deallocate", |
|
"dec", |
|
"decimal", |
|
"decfloat", |
|
"declare", |
|
"default", |
|
"define", |
|
"delete", |
|
"dense_rank", |
|
"deref", |
|
"describe", |
|
"deterministic", |
|
"disconnect", |
|
"distinct", |
|
"double", |
|
"drop", |
|
"dynamic", |
|
"each", |
|
"element", |
|
"else", |
|
"empty", |
|
"end", |
|
"end_frame", |
|
"end_partition", |
|
"end-exec", |
|
"equals", |
|
"escape", |
|
"every", |
|
"except", |
|
"exec", |
|
"execute", |
|
"exists", |
|
"exp", |
|
"external", |
|
"extract", |
|
"false", |
|
"fetch", |
|
"filter", |
|
"first_value", |
|
"float", |
|
"floor", |
|
"for", |
|
"foreign", |
|
"frame_row", |
|
"free", |
|
"from", |
|
"full", |
|
"function", |
|
"fusion", |
|
"get", |
|
"global", |
|
"grant", |
|
"group", |
|
"grouping", |
|
"groups", |
|
"having", |
|
"hold", |
|
"hour", |
|
"identity", |
|
"in", |
|
"indicator", |
|
"initial", |
|
"inner", |
|
"inout", |
|
"insensitive", |
|
"insert", |
|
"int", |
|
"integer", |
|
"intersect", |
|
"intersection", |
|
"interval", |
|
"into", |
|
"is", |
|
"join", |
|
"json_array", |
|
"json_arrayagg", |
|
"json_exists", |
|
"json_object", |
|
"json_objectagg", |
|
"json_query", |
|
"json_table", |
|
"json_table_primitive", |
|
"json_value", |
|
"lag", |
|
"language", |
|
"large", |
|
"last_value", |
|
"lateral", |
|
"lead", |
|
"leading", |
|
"left", |
|
"like", |
|
"like_regex", |
|
"listagg", |
|
"ln", |
|
"local", |
|
"localtime", |
|
"localtimestamp", |
|
"log", |
|
"log10", |
|
"lower", |
|
"match", |
|
"match_number", |
|
"match_recognize", |
|
"matches", |
|
"max", |
|
"member", |
|
"merge", |
|
"method", |
|
"min", |
|
"minute", |
|
"mod", |
|
"modifies", |
|
"module", |
|
"month", |
|
"multiset", |
|
"national", |
|
"natural", |
|
"nchar", |
|
"nclob", |
|
"new", |
|
"no", |
|
"none", |
|
"normalize", |
|
"not", |
|
"nth_value", |
|
"ntile", |
|
"null", |
|
"nullif", |
|
"numeric", |
|
"octet_length", |
|
"occurrences_regex", |
|
"of", |
|
"offset", |
|
"old", |
|
"omit", |
|
"on", |
|
"one", |
|
"only", |
|
"open", |
|
"or", |
|
"order", |
|
"out", |
|
"outer", |
|
"over", |
|
"overlaps", |
|
"overlay", |
|
"parameter", |
|
"partition", |
|
"pattern", |
|
"per", |
|
"percent", |
|
"percent_rank", |
|
"percentile_cont", |
|
"percentile_disc", |
|
"period", |
|
"portion", |
|
"position", |
|
"position_regex", |
|
"power", |
|
"precedes", |
|
"precision", |
|
"prepare", |
|
"primary", |
|
"procedure", |
|
"ptf", |
|
"range", |
|
"rank", |
|
"reads", |
|
"real", |
|
"recursive", |
|
"ref", |
|
"references", |
|
"referencing", |
|
"regr_avgx", |
|
"regr_avgy", |
|
"regr_count", |
|
"regr_intercept", |
|
"regr_r2", |
|
"regr_slope", |
|
"regr_sxx", |
|
"regr_sxy", |
|
"regr_syy", |
|
"release", |
|
"result", |
|
"return", |
|
"returns", |
|
"revoke", |
|
"right", |
|
"rollback", |
|
"rollup", |
|
"row", |
|
"row_number", |
|
"rows", |
|
"running", |
|
"savepoint", |
|
"scope", |
|
"scroll", |
|
"search", |
|
"second", |
|
"seek", |
|
"select", |
|
"sensitive", |
|
"session_user", |
|
"set", |
|
"show", |
|
"similar", |
|
"sin", |
|
"sinh", |
|
"skip", |
|
"smallint", |
|
"some", |
|
"specific", |
|
"specifictype", |
|
"sql", |
|
"sqlexception", |
|
"sqlstate", |
|
"sqlwarning", |
|
"sqrt", |
|
"start", |
|
"static", |
|
"stddev_pop", |
|
"stddev_samp", |
|
"submultiset", |
|
"subset", |
|
"substring", |
|
"substring_regex", |
|
"succeeds", |
|
"sum", |
|
"symmetric", |
|
"system", |
|
"system_time", |
|
"system_user", |
|
"table", |
|
"tablesample", |
|
"tan", |
|
"tanh", |
|
"then", |
|
"time", |
|
"timestamp", |
|
"timezone_hour", |
|
"timezone_minute", |
|
"to", |
|
"trailing", |
|
"translate", |
|
"translate_regex", |
|
"translation", |
|
"treat", |
|
"trigger", |
|
"trim", |
|
"trim_array", |
|
"true", |
|
"truncate", |
|
"uescape", |
|
"union", |
|
"unique", |
|
"unknown", |
|
"unnest", |
|
"update ", |
|
"upper", |
|
"user", |
|
"using", |
|
"value", |
|
"values", |
|
"value_of", |
|
"var_pop", |
|
"var_samp", |
|
"varbinary", |
|
"varchar", |
|
"varying", |
|
"versioning", |
|
"when", |
|
"whenever", |
|
"where", |
|
"width_bucket", |
|
"window", |
|
"with", |
|
"within", |
|
"without", |
|
"year", |
|
]; |
|
|
|
// these are reserved words we have identified to be functions |
|
// and should only be highlighted in a dispatch-like context |
|
// ie, array_agg(...), etc. |
|
const RESERVED_FUNCTIONS = [ |
|
"abs", |
|
"acos", |
|
"array_agg", |
|
"asin", |
|
"atan", |
|
"avg", |
|
"cast", |
|
"ceil", |
|
"ceiling", |
|
"coalesce", |
|
"corr", |
|
"cos", |
|
"cosh", |
|
"count", |
|
"covar_pop", |
|
"covar_samp", |
|
"cume_dist", |
|
"dense_rank", |
|
"deref", |
|
"element", |
|
"exp", |
|
"extract", |
|
"first_value", |
|
"floor", |
|
"json_array", |
|
"json_arrayagg", |
|
"json_exists", |
|
"json_object", |
|
"json_objectagg", |
|
"json_query", |
|
"json_table", |
|
"json_table_primitive", |
|
"json_value", |
|
"lag", |
|
"last_value", |
|
"lead", |
|
"listagg", |
|
"ln", |
|
"log", |
|
"log10", |
|
"lower", |
|
"max", |
|
"min", |
|
"mod", |
|
"nth_value", |
|
"ntile", |
|
"nullif", |
|
"percent_rank", |
|
"percentile_cont", |
|
"percentile_disc", |
|
"position", |
|
"position_regex", |
|
"power", |
|
"rank", |
|
"regr_avgx", |
|
"regr_avgy", |
|
"regr_count", |
|
"regr_intercept", |
|
"regr_r2", |
|
"regr_slope", |
|
"regr_sxx", |
|
"regr_sxy", |
|
"regr_syy", |
|
"row_number", |
|
"sin", |
|
"sinh", |
|
"sqrt", |
|
"stddev_pop", |
|
"stddev_samp", |
|
"substring", |
|
"substring_regex", |
|
"sum", |
|
"tan", |
|
"tanh", |
|
"translate", |
|
"translate_regex", |
|
"treat", |
|
"trim", |
|
"trim_array", |
|
"unnest", |
|
"upper", |
|
"value_of", |
|
"var_pop", |
|
"var_samp", |
|
"width_bucket", |
|
]; |
|
|
|
// these functions can |
|
const POSSIBLE_WITHOUT_PARENS = [ |
|
"current_catalog", |
|
"current_date", |
|
"current_default_transform_group", |
|
"current_path", |
|
"current_role", |
|
"current_schema", |
|
"current_transform_group_for_type", |
|
"current_user", |
|
"session_user", |
|
"system_time", |
|
"system_user", |
|
"current_time", |
|
"localtime", |
|
"current_timestamp", |
|
"localtimestamp" |
|
]; |
|
|
|
// those exist to boost relevance making these very |
|
// "SQL like" keyword combos worth +1 extra relevance |
|
const COMBOS = [ |
|
"create table", |
|
"insert into", |
|
"primary key", |
|
"foreign key", |
|
"not null", |
|
"alter table", |
|
"add constraint", |
|
"grouping sets", |
|
"on overflow", |
|
"character set", |
|
"respect nulls", |
|
"ignore nulls", |
|
"nulls first", |
|
"nulls last", |
|
"depth first", |
|
"breadth first" |
|
]; |
|
|
|
const FUNCTIONS = RESERVED_FUNCTIONS; |
|
|
|
const KEYWORDS = [...RESERVED_WORDS, ...NON_RESERVED_WORDS].filter((keyword) => { |
|
return !RESERVED_FUNCTIONS.includes(keyword); |
|
}); |
|
|
|
const VARIABLE = { |
|
className: "variable", |
|
begin: /@[a-z0-9]+/, |
|
}; |
|
|
|
const OPERATOR = { |
|
className: "operator", |
|
begin: /[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, |
|
relevance: 0, |
|
}; |
|
|
|
const FUNCTION_CALL = { |
|
begin: concat(/\b/, either(...FUNCTIONS), /\s*\(/), |
|
keywords: { |
|
built_in: FUNCTIONS |
|
} |
|
}; |
|
|
|
// keywords with less than 3 letters are reduced in relevancy |
|
function reduceRelevancy(list, {exceptions, when} = {}) { |
|
const qualifyFn = when; |
|
exceptions = exceptions || []; |
|
return list.map((item) => { |
|
if (item.match(/\|\d+$/) || exceptions.includes(item)) { |
|
return item; |
|
} else if (qualifyFn(item)) { |
|
return `${item}|0`; |
|
} else { |
|
return item; |
|
} |
|
}); |
|
} |
|
|
|
return { |
|
name: 'SQL', |
|
case_insensitive: true, |
|
// does not include {} or HTML tags `</` |
|
illegal: /[{}]|<\//, |
|
keywords: { |
|
$pattern: /\b[\w\.]+/, |
|
keyword: |
|
reduceRelevancy(KEYWORDS, { when: (x) => x.length < 3 }), |
|
literal: LITERALS, |
|
type: TYPES, |
|
built_in: POSSIBLE_WITHOUT_PARENS |
|
}, |
|
contains: [ |
|
{ |
|
begin: either(...COMBOS), |
|
keywords: { |
|
$pattern: /[\w\.]+/, |
|
keyword: KEYWORDS.concat(COMBOS), |
|
literal: LITERALS, |
|
type: TYPES |
|
}, |
|
}, |
|
{ |
|
className: "type", |
|
begin: either(...MULTI_WORD_TYPES) |
|
}, |
|
FUNCTION_CALL, |
|
VARIABLE, |
|
STRING, |
|
QUOTED_IDENTIFIER, |
|
hljs.C_NUMBER_MODE, |
|
hljs.C_BLOCK_COMMENT_MODE, |
|
COMMENT_MODE, |
|
OPERATOR |
|
] |
|
}; |
|
} |
|
|
|
module.exports = sql;
|
|
|