Skip to content
Open

Add KDL #4082

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@
"title": "Julia",
"owner": "cdagnino"
},
"kdl": {
"title": "KDL",
"owner": "jbr"
},
"keepalived": {
"title": "Keepalived Configure",
"owner": "dev-itsheng"
Expand Down
84 changes: 84 additions & 0 deletions src/languages/kdl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/** @type {import('../types.d.ts').LanguageProto<'kdl'>} */
export default {
id: 'kdl',
grammar () {
// Characters that are NOT valid inside a bare identifier (KDL v2 set,
// which is the more restrictive of v1/v2 in the ways that matter for
// highlighting). Used as a negated character class.
const NON_ID = '\\s\\\\/(){}\\[\\]"#;=';
const IDENT_BODY = `[^${NON_ID}]`;

// Bare identifier. The dotted/signed first-character rules from the spec
// are folded into three alternatives, longest-form first so the regex
// engine doesn't commit to a one-char match when more is available.
const IDENT =
'(?:' +
// optional sign, dot, then a non-digit body
`[+\\-]?\\.(?:[^${NON_ID}0-9]${IDENT_BODY}*)?` +
'|' +
// sign, then a non-digit, non-dot body
`[+\\-](?:[^${NON_ID}0-9.]${IDENT_BODY}*)?` +
'|' +
// plain start: non-digit, non-sign, non-dot, non-special
`[^${NON_ID}0-9+\\-.]${IDENT_BODY}*` +
')';

// Single-line quoted string. Permissive escape handling: a backslash plus
// any single character is treated as an escape, no further structure.
// (Being more specific about `\u{...}` causes regex-pattern ambiguity.)
const QUOTED = '"(?:\\\\[\\s\\S]|[^"\\\\\\r\\n])*"';

// Anything that can fill an identifier slot (node name, property key,
// type annotation name).
const STRINGY = `(?:${QUOTED}|${IDENT})`;

return {
'comment': {
pattern: /\/\/.*|\/\*[\s\S]*?\*\//,
greedy: true,
},
'slashdash': {
pattern: /\/-/,
alias: 'comment',
},
'raw-string': {
// v2 raw strings: one or more `#`s, then `"..."` or `"""..."""`.
// v1 raw strings: `r`, then zero or more `#`s, then quotes.
// Backreferences enforce matching hash counts on both sides.
pattern: /(#+)"""[\s\S]*?"""\1|(#+)"[\s\S]*?"\2|r(#*)"""[\s\S]*?"""\3|r(#*)"[\s\S]*?"\4/,
greedy: true,
alias: 'string',
},
'property': {
// Must come before `string` so quoted-string keys win over the
// generic string pattern.
pattern: RegExp(`${STRINGY}(?=\\s*=[^=])`),
greedy: true,
alias: 'attr-name',
},
'string': {
pattern: /"""[\s\S]*?"""|"(?:\\[\s\S]|[^"\\\r\n])*"/,
greedy: true,
},
'type-annotation': {
// Must come before `number`/`keyword` so digits or keyword-shaped
// type names (like `u8` or `true`) aren't shredded by those rules.
pattern: RegExp(`\\(\\s*${STRINGY}\\s*\\)`),
inside: {
'class-name': RegExp(STRINGY),
'punctuation': /[()]/,
},
},
'keyword': /#(?:true|false|null|-inf|inf|nan)\b|\b(?:true|false|null)\b/,
'number': /[+-]?(?:0x[\da-fA-F][\da-fA-F_]*|0o[0-7][0-7_]*|0b[01][01_]*|\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)/,
'tag': {
// First identifier on a line, or right after `{`, `;`, or a
// type annotation's closing `)`. Handles whitespace in between.
pattern: RegExp(`(^[\\t ]*|[{;)][\\t ]*)${STRINGY}`, 'm'),
lookbehind: true,
greedy: true,
},
'punctuation': /[{};=\\]/,
};
},
};
38 changes: 38 additions & 0 deletions tests/languages/kdl/boolean_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
node #true
node #false
node true
node false
node a=#true b=#false
node a=true b=false

----------------------------------------------------

[
["tag", "node"],
["keyword", "#true"],

["tag", "node"],
["keyword", "#false"],

["tag", "node"],
["keyword", "true"],

["tag", "node"],
["keyword", "false"],

["tag", "node"],
["property", "a"],
["punctuation", "="],
["keyword", "#true"],
["property", "b"],
["punctuation", "="],
["keyword", "#false"],

["tag", "node"],
["property", "a"],
["punctuation", "="],
["keyword", "true"],
["property", "b"],
["punctuation", "="],
["keyword", "false"]
]
15 changes: 15 additions & 0 deletions tests/languages/kdl/comment_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// single-line comment
/* multi
line
comment */
node // trailing comment
node /* inline */ arg

----------------------------------------------------

[
["comment", "// single-line comment"],
["comment", "/* multi\r\n line\r\n comment */"],
["tag", "node"], ["comment", "// trailing comment"],
["tag", "node"], ["comment", "/* inline */"], " arg"
]
24 changes: 24 additions & 0 deletions tests/languages/kdl/null_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
node #null
node null
node key=#null
node key=null

----------------------------------------------------

[
["tag", "node"],
["keyword", "#null"],

["tag", "node"],
["keyword", "null"],

["tag", "node"],
["property", "key"],
["punctuation", "="],
["keyword", "#null"],

["tag", "node"],
["property", "key"],
["punctuation", "="],
["keyword", "null"]
]
35 changes: 35 additions & 0 deletions tests/languages/kdl/number_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
node 0
node 42
node -42
node +42
node 3.14
node -3.14
node 1.5e10
node 2.5E-3
node 1_000_000
node 0xDEAD_BEEF
node 0o755
node 0b1010_0101
node #inf
node #-inf
node #nan

----------------------------------------------------

[
["tag", "node"], ["number", "0"],
["tag", "node"], ["number", "42"],
["tag", "node"], ["number", "-42"],
["tag", "node"], ["number", "+42"],
["tag", "node"], ["number", "3.14"],
["tag", "node"], ["number", "-3.14"],
["tag", "node"], ["number", "1.5e10"],
["tag", "node"], ["number", "2.5E-3"],
["tag", "node"], ["number", "1_000_000"],
["tag", "node"], ["number", "0xDEAD_BEEF"],
["tag", "node"], ["number", "0o755"],
["tag", "node"], ["number", "0b1010_0101"],
["tag", "node"], ["keyword", "#inf"],
["tag", "node"], ["keyword", "#-inf"],
["tag", "node"], ["keyword", "#nan"]
]
37 changes: 37 additions & 0 deletions tests/languages/kdl/property_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
node key=1
node key="value"
node a=1 b=2
node key = 1
node "quoted key"="value"

----------------------------------------------------

[
["tag", "node"],
["property", "key"],
["punctuation", "="],
["number", "1"],

["tag", "node"],
["property", "key"],
["punctuation", "="],
["string", "\"value\""],

["tag", "node"],
["property", "a"],
["punctuation", "="],
["number", "1"],
["property", "b"],
["punctuation", "="],
["number", "2"],

["tag", "node"],
["property", "key"],
["punctuation", "="],
["number", "1"],

["tag", "node"],
["property", "\"quoted key\""],
["punctuation", "="],
["string", "\"value\""]
]
27 changes: 27 additions & 0 deletions tests/languages/kdl/raw-string_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
node #"v2 raw with \n literal"#
node ##"v2 raw with "# inside"##
node #"""
multi
line raw
"""#
node r"v1 raw \n literal"
node r##"v1 raw with "# inside"##

----------------------------------------------------

[
["tag", "node"],
["raw-string", "#\"v2 raw with \\n literal\"#"],

["tag", "node"],
["raw-string", "##\"v2 raw with \"# inside\"##"],

["tag", "node"],
["raw-string", "#\"\"\"\r\n multi\r\n line raw\r\n \"\"\"#"],

["tag", "node"],
["raw-string", "r\"v1 raw \\n literal\""],

["tag", "node"],
["raw-string", "r##\"v1 raw with \"# inside\"##"]
]
36 changes: 36 additions & 0 deletions tests/languages/kdl/slashdash_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/- commented-node
node /- 1 2 3
node /- key=value
node {
/- commented-child
real-child
}

----------------------------------------------------

[
["slashdash", "/-"],
" commented-node\r\n",

["tag", "node"],
["slashdash", "/-"],
["number", "1"],
["number", "2"],
["number", "3"],

["tag", "node"],
["slashdash", "/-"],
["property", "key"],
["punctuation", "="],
"value\r\n",

["tag", "node"],
["punctuation", "{"],

["slashdash", "/-"],
" commented-child\r\n ",

["tag", "real-child"],

["punctuation", "}"]
]
27 changes: 27 additions & 0 deletions tests/languages/kdl/string_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
node "hello"
node "with \"escaped\" quotes"
node "newline\nhere"
node "unicode \u{1F4A9}"
node """
multi-line
string
"""

----------------------------------------------------

[
["tag", "node"],
["string", "\"hello\""],

["tag", "node"],
["string", "\"with \\\"escaped\\\" quotes\""],

["tag", "node"],
["string", "\"newline\\nhere\""],

["tag", "node"],
["string", "\"unicode \\u{1F4A9}\""],

["tag", "node"],
["string", "\"\"\"\r\n multi-line\r\n string\r\n \"\"\""]
]
27 changes: 27 additions & 0 deletions tests/languages/kdl/tag_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
node
my-node
node1
parent {
child1
child2
}
parent { child1; child2 }

----------------------------------------------------

[
["tag", "node"],
["tag", "my-node"],
["tag", "node1"],
["tag", "parent"],
["punctuation", "{"],
["tag", "child1"],
["tag", "child2"],
["punctuation", "}"],
["tag", "parent"],
["punctuation", "{"],
["tag", "child1"],
["punctuation", ";"],
["tag", "child2"],
["punctuation", "}"]
]
Loading