hivecode-mcp 0.8.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lang-brace.js CHANGED
@@ -1,174 +1,240 @@
1
- // Brace-family language provider for ICR — a dependency-free, language-agnostic
2
- // structural splitter for C-style languages (TypeScript, Go, Rust, Java, C/C++,
3
- // C#, Swift, Kotlin, Scala, PHP, Dart, …). It implements the ICR provider contract
4
- // { id, exts, parses, units, declaredNames, splitUnit, parsesUnit } so the SAME
5
- // merge engine in icr.js merges these languages by structure — different top-level
6
- // declarations merge cleanly, the same declaration edited two ways is a named
7
- // conflict, and edits to different members inside one class/function merge via the
8
- // engine's finer-grained inner merge (splitUnit).
9
- //
10
- // It is a heuristic scanner, not a full parser: it tracks strings, line/block
11
- // comments, and bracket depth to find top-level declarations and their byte ranges.
12
- // This gives real structural merge and an approximate parses() (balanced delimiters)
13
- // — honest and useful today; a tree-sitter provider can later replace it behind the
14
- // same interface with zero engine changes.
15
-
16
- const LINE = ['//']
17
- const OPEN = { '{': '}', '(': ')', '[': ']' }
18
- const CLOSE = { '}': '{', ')': '(', ']': '[' }
19
-
20
- // Walk `src` once. `at(i)` returns the index just past a string or comment starting
21
- // at i, or -1 if none starts there — so callers can skip over them uniformly.
22
- function scannerAt(src, strings) {
23
- const n = src.length
24
- return function at(i) {
25
- if (src[i] === '/' && src[i + 1] === '*') { let j = i + 2; while (j < n && !(src[j] === '*' && src[j + 1] === '/')) j++; return Math.min(n, j + 2) }
26
- for (const lc of LINE) if (src.startsWith(lc, i)) { let j = i + lc.length; while (j < n && src[j] !== '\n') j++; return j }
27
- if (strings.includes(src[i])) { const q = src[i]; let j = i + 1; while (j < n) { if (src[j] === '\\') { j += 2; continue } if (src[j] === q) { j++; break } j++ } return j }
28
- return -1
29
- }
30
- }
31
-
32
- const isWS = (c) => c === ' ' || c === '\t' || c === '\r' || c === '\n'
33
-
34
- // Extract top-level units [{start,end}] from src[from..to]. A unit is a maximal
35
- // declaration/statement at bracket depth 0: either a block (signature + balanced
36
- // {…}) or a statement ending at ';' or end-of-line.
37
- function topUnits(src, strings, from = 0, to = src.length) {
38
- const at = scannerAt(src, strings)
39
- const units = []
40
- let i = from
41
- while (i < to) {
42
- while (i < to && isWS(src[i])) i++
43
- if (i >= to) break
44
- // A standalone comment before a declaration belongs to the GAP (kept verbatim by
45
- // the engine's splice), so skip it without starting a unit.
46
- if ((src[i] === '/' && (src[i + 1] === '/' || src[i + 1] === '*'))) { const s = at(i); if (s > i) { i = s; continue } }
47
- const start = i
48
- let depth = 0, sawBrace = false
49
- while (i < to) {
50
- const s = at(i)
51
- if (s > i) { i = s; continue } // skip string / comment
52
- const c = src[i]
53
- if (OPEN[c]) { if (c === '{') sawBrace = true; depth++; i++; continue }
54
- if (CLOSE[c]) { depth--; i++; if (depth <= 0 && sawBrace) { while (i < to && (src[i] === ' ' || src[i] === '\t')) i++; if (src[i] === ';') i++; break } continue }
55
- if (depth === 0) {
56
- if (c === ';') { i++; break }
57
- if (c === '\n' && !sawBrace) break
58
- }
59
- i++
60
- }
61
- units.push({ start, end: i })
62
- }
63
- return units
64
- }
65
-
66
- const DECL = /\b(function|func|fn|def|fun|class|interface|struct|enum|trait|impl|type|namespace|module|package|object|record|protocol|actor|extension)\s+([A-Za-z_$][\w$]*)/
67
- const VARD = /\b(const|let|var|val|static|final)\s+([A-Za-z_$][\w$]*)/
68
- // Method/function signature, including TYPE-FIRST forms (`int a()`, `public static
69
- // void main(String[] a)`, `std::string name()`): optional decorators + any number of
70
- // modifiers + an optional return-type token, then NAME(args){. The captured name is
71
- // the identifier directly before `(`.
72
- const METH = /^(?:@[\w.()]+\s+)*(?:(?:public|private|protected|internal|static|async|final|override|open|pub|suspend|inline|virtual|export|default|abstract|sealed|unsafe|extern|synchronized|native|constexpr)\s+)*(?:(?:function|fn|func|fun)\s+)?(?:[A-Za-z_$][\w$<>\[\].,:&*\s]*?\s+)?([A-Za-z_$][\w$]*)\s*(?:<[^>]*>)?\s*\([^;{]*\)\s*(?:->[^{]+|:[^={]+)?\s*\{/
73
- // control-flow headers also look like `name (…) {` — never key them as methods
74
- const CTRL = new Set(['if', 'for', 'while', 'switch', 'catch', 'do', 'else', 'try', 'return', 'new', 'throw', 'match', 'select', 'when', 'until', 'lock', 'using', 'foreach', 'with'])
75
-
76
- function keyOf(text) {
77
- const head = text.replace(/^\s+/, '')
78
- let m = head.match(DECL); if (m) return m[1] + ':' + m[2]
79
- m = head.match(METH); if (m && !CTRL.has(m[1])) return 'method:' + m[1]
80
- m = head.match(VARD); if (m) return 'var:' + m[2]
81
- return 'stmt:' + head.split('\n')[0].trim().replace(/\s+/g, ' ')
82
- }
83
-
84
- // De-duplicate keys deterministically (repeated statements / same-named units) so the
85
- // engine's keyed merge never silently drops one. Order is stable → convergent.
86
- function keyedUnits(raw, src) {
87
- const seen = new Map(), out = []
88
- for (const u of raw) {
89
- const text = src.slice(u.start, u.end)
90
- let k = keyOf(text)
91
- const c = (seen.get(k) || 0) + 1; seen.set(k, c)
92
- if (c > 1) k += '#' + c
93
- out.push({ key: k, text, start: u.start, end: u.end })
94
- }
95
- return out
96
- }
97
-
98
- // Approximate parse check: delimiters balanced and no unterminated string/comment,
99
- // ignoring the contents of strings and comments.
100
- function balanced(src, strings) {
101
- const at = scannerAt(src, strings)
102
- const stack = []
103
- let i = 0
104
- while (i < src.length) {
105
- const s = at(i)
106
- if (s > i) { if (s > src.length) return false; i = s; continue }
107
- const c = src[i]
108
- if (OPEN[c]) stack.push(c)
109
- else if (CLOSE[c]) { if (stack.pop() !== CLOSE[c]) return false }
110
- i++
111
- }
112
- return stack.length === 0
113
- }
114
-
115
- export function makeBraceLanguage({ id, exts, strings = ['"', "'", '`'] }) {
116
- const provider = {
117
- id,
118
- exts,
119
- parses: (src) => balanced(String(src == null ? '' : src), strings),
120
- units: (src) => keyedUnits(topUnits(String(src), strings), String(src)),
121
- declaredNames: (src) => {
122
- const names = new Set()
123
- for (const u of keyedUnits(topUnits(String(src), strings), String(src))) {
124
- const m = u.key.match(/^(?:[a-z]+):([A-Za-z_$][\w$]*)/)
125
- if (m && !u.key.startsWith('stmt:')) names.add(m[1])
126
- }
127
- return names
128
- },
129
- parsesUnit: (src) => balanced(String(src), strings),
130
- // Finer granularity: descend one level into a block declaration so two agents
131
- // editing DIFFERENT members of the same class/function merge instead of clashing.
132
- splitUnit: (text) => {
133
- const src = String(text)
134
- // Only descend into NAMED containers (class/struct/impl/…), whose members are
135
- // keyed by name — so editing different members merges. A function/method body is
136
- // just statements (no stable keys); descending there would falsely merge two
137
- // edits to the same code, so we DON'T — the whole unit becomes a clean conflict.
138
- if (!/\b(class|interface|struct|enum|trait|impl|namespace|module|object|record|extension|protocol|actor)\b/.test(src.split('{')[0]))
139
- return null
140
- const at = scannerAt(src, strings)
141
- let i = 0, open = -1
142
- while (i < src.length) { const s = at(i); if (s > i) { i = s; continue } if (src[i] === '{') { open = i; break } i++ }
143
- if (open < 0) return null
144
- // find matching close
145
- let depth = 0, j = open, close = -1
146
- while (j < src.length) { const s = at(j); if (s > j) { j = s; continue } const c = src[j]; if (c === '{') depth++; else if (c === '}') { depth--; if (depth === 0) { close = j; break } } j++ }
147
- if (close < 0) return null
148
- const sig = src.slice(0, open)
149
- const body = src.slice(open + 1, close)
150
- const inner = keyedUnits(topUnits(body, strings), body)
151
- // re-base inner ranges into `body` coordinates are already correct (topUnits used body)
152
- return { sig, open: '{', close: src.slice(close), body, units: inner, join: '' }
153
- },
154
- }
155
- return provider
156
- }
157
-
158
- // Ready-made providers covering the common C-family languages. One provider can claim
159
- // many extensions; comment/string syntax defaults fit the whole family (edge cases like
160
- // Rust raw strings / lifetimes are tolerated — worst case a unit is merged coarsely).
161
- export const braceLanguages = [
162
- makeBraceLanguage({ id: 'ts', exts: ['.ts', '.tsx', '.mts', '.cts'] }),
163
- makeBraceLanguage({ id: 'jsx', exts: ['.jsx'] }),
164
- makeBraceLanguage({ id: 'go', exts: ['.go'], strings: ['"', '`'] }),
165
- makeBraceLanguage({ id: 'rust', exts: ['.rs'] }),
166
- makeBraceLanguage({ id: 'java', exts: ['.java'] }),
167
- makeBraceLanguage({ id: 'c', exts: ['.c', '.h', '.cpp', '.hpp', '.cc', '.hh', '.cxx'] }),
168
- makeBraceLanguage({ id: 'csharp', exts: ['.cs'] }),
169
- makeBraceLanguage({ id: 'swift', exts: ['.swift'] }),
170
- makeBraceLanguage({ id: 'kotlin', exts: ['.kt', '.kts'] }),
171
- makeBraceLanguage({ id: 'scala', exts: ['.scala'] }),
172
- makeBraceLanguage({ id: 'php', exts: ['.php'] }),
173
- makeBraceLanguage({ id: 'dart', exts: ['.dart'] }),
174
- ]
1
+ // Brace-family language provider for ICR — a dependency-free, language-agnostic
2
+ // structural splitter for C-style languages (TypeScript, Go, Rust, Java, C/C++,
3
+ // C#, Swift, Kotlin, Scala, PHP, Dart, …). It implements the ICR provider contract
4
+ // { id, exts, parses, units, declaredNames, splitUnit, parsesUnit } so the SAME
5
+ // merge engine in icr.js merges these languages by structure — different top-level
6
+ // declarations merge cleanly, the same declaration edited two ways is a named
7
+ // conflict, and edits to different members inside one class/function merge via the
8
+ // engine's finer-grained inner merge (splitUnit).
9
+ //
10
+ // It is a heuristic scanner, not a full parser: it tracks strings, line/block
11
+ // comments, and bracket depth to find top-level declarations and their byte ranges.
12
+ // This gives real structural merge and an approximate parses() (balanced delimiters)
13
+ // — honest and useful today; a tree-sitter provider can later replace it behind the
14
+ // same interface with zero engine changes.
15
+
16
+ const LINE = ['//']
17
+ const OPEN = { '{': '}', '(': ')', '[': ']' }
18
+ const CLOSE = { '}': '{', ')': '(', ']': '[' }
19
+
20
+ // Walk `src` once. `at(i)` returns the index just past a string or comment starting
21
+ // at i, or -1 if none starts there — so callers can skip over them uniformly.
22
+ function scannerAt(src, strings) {
23
+ const n = src.length
24
+ return function at(i) {
25
+ if (src[i] === '/' && src[i + 1] === '*') { let j = i + 2; while (j < n && !(src[j] === '*' && src[j + 1] === '/')) j++; return Math.min(n, j + 2) }
26
+ for (const lc of LINE) if (src.startsWith(lc, i)) { let j = i + lc.length; while (j < n && src[j] !== '\n') j++; return j }
27
+ if (strings.includes(src[i])) { const q = src[i]; let j = i + 1; while (j < n) { if (src[j] === '\\') { j += 2; continue } if (src[j] === q) { j++; break } j++ } return j }
28
+ return -1
29
+ }
30
+ }
31
+
32
+ const isWS = (c) => c === ' ' || c === '\t' || c === '\r' || c === '\n'
33
+
34
+ // Extract top-level units [{start,end}] from src[from..to]. A unit is a maximal
35
+ // declaration/statement at bracket depth 0: either a block (signature + balanced
36
+ // {…}) or a statement ending at ';' or end-of-line.
37
+ function topUnits(src, strings, from = 0, to = src.length) {
38
+ const at = scannerAt(src, strings)
39
+ const units = []
40
+ let i = from
41
+ while (i < to) {
42
+ while (i < to && isWS(src[i])) i++
43
+ if (i >= to) break
44
+
45
+ const start = i
46
+ let depth = 0, sawBrace = false
47
+ while (i < to) {
48
+ const s = at(i)
49
+ if (s > i) { i = s; continue } // skip string / comment
50
+ const c = src[i]
51
+ if (OPEN[c]) { if (c === '{') sawBrace = true; depth++; i++; continue }
52
+ if (CLOSE[c]) { depth--; i++; if (depth <= 0 && sawBrace) { while (i < to && (src[i] === ' ' || src[i] === '\t')) i++; if (src[i] === ';') i++; break } continue }
53
+ if (depth === 0) {
54
+ if (c === ';') { i++; break }
55
+ if (c === '\n' && !sawBrace) break
56
+ }
57
+ i++
58
+ }
59
+ units.push({ start, end: i })
60
+ }
61
+ return units
62
+ }
63
+
64
+ const DECL = /\b(function|func|fn|def|fun|class|interface|struct|enum|trait|impl|type|namespace|module|package|object|record|protocol|actor|extension)\s+([A-Za-z_$][\w$]*)/
65
+ const VARD = /\b(const|let|var|val|static|final)\s+([A-Za-z_$][\w$]*)/
66
+ // Method/function signature, including TYPE-FIRST forms (`int a()`, `public static
67
+ // void main(String[] a)`, `std::string name()`): optional decorators + any number of
68
+ // modifiers + an optional return-type token, then NAME(args){. The captured name is
69
+ // the identifier directly before `(`.
70
+ const METH = /^(?:@[\w.()]+\s+)*(?:(?:public|private|protected|internal|static|async|final|override|open|pub|suspend|inline|virtual|export|default|abstract|sealed|unsafe|extern|synchronized|native|constexpr)\s+)*(?:(?:function|fn|func|fun)\s+)?(?:[A-Za-z_$][\w$<>\[\].,:&*\s]*?\s+)?([A-Za-z_$][\w$]*)\s*(?:<[^>]*>)?\s*\([^;{]*\)\s*(?:->[^{]+|:[^={]+)?\s*\{/
71
+ // control-flow headers also look like `name (…) {` — never key them as methods
72
+ const CTRL = new Set(['if', 'for', 'while', 'switch', 'catch', 'do', 'else', 'try', 'return', 'new', 'throw', 'match', 'select', 'when', 'until', 'lock', 'using', 'foreach', 'with'])
73
+
74
+ function keyOf(text) {
75
+ const head = text.replace(/^\s+/, '')
76
+ let m = head.match(DECL); if (m) return m[1] + ':' + m[2]
77
+ m = head.match(METH); if (m && !CTRL.has(m[1])) return 'method:' + m[1]
78
+ m = head.match(VARD); if (m) return 'var:' + m[2]
79
+ return 'stmt:' + head.split('\n')[0].trim().replace(/\s+/g, ' ')
80
+ }
81
+
82
+ // De-duplicate keys deterministically (repeated statements / same-named units) so the
83
+ // engine's keyed merge never silently drops one. Order is stable → convergent.
84
+ function keyedUnits(raw, src) {
85
+ const seen = new Map(), out = []
86
+ for (const u of raw) {
87
+ const text = src.slice(u.start, u.end)
88
+ let k = keyOf(text)
89
+ const c = (seen.get(k) || 0) + 1; seen.set(k, c)
90
+ if (c > 1) k += '#' + c
91
+ out.push({ key: k, text, start: u.start, end: u.end })
92
+ }
93
+ return out
94
+ }
95
+
96
+ // Generic lexer for the token-level inner merge + the intent layer. Tokens are
97
+ // identifiers, numbers, whole strings, and single operator chars; comments live in
98
+ // the gaps (same contract as the JS provider: a comment-only edit is a no-op here).
99
+ // Returns [{start,end,k}] — k is the raw text, so any content change is a token change.
100
+ function lexTokens(src, strings) {
101
+ const at = scannerAt(src, strings)
102
+ const out = []
103
+ const n = src.length
104
+ let i = 0
105
+ while (i < n) {
106
+ if (isWS(src[i])) { i++; continue }
107
+ const j = at(i)
108
+ if (j > i) {
109
+ if (src[i] === '/' || src[i] === '#') { i = j; continue } // comment → gap
110
+ out.push({ start: i, end: j, k: src.slice(i, j) }); i = j; continue // string → one token
111
+ }
112
+ const c = src[i]
113
+ if (/[A-Za-z_$]/.test(c)) { let e = i + 1; while (e < n && /[\w$]/.test(src[e])) e++; out.push({ start: i, end: e, k: src.slice(i, e) }); i = e; continue }
114
+ if (/[0-9]/.test(c)) { let e = i + 1; while (e < n && /[\w.]/.test(src[e])) e++; out.push({ start: i, end: e, k: src.slice(i, e) }); i = e; continue }
115
+ out.push({ start: i, end: i + 1, k: c }); i++
116
+ }
117
+ return out
118
+ }
119
+
120
+ // Is this token a REFERENCE-position identifier (not property access `.name`)?
121
+ function isRefToken(src, t) {
122
+ if (!/^[A-Za-z_$][\w$]*$/.test(t.k)) return false
123
+ let p = t.start - 1
124
+ while (p >= 0 && isWS(src[p])) p--
125
+ return !(p >= 0 && src[p] === '.')
126
+ }
127
+
128
+ // Approximate parse check: delimiters balanced and no unterminated string/comment,
129
+ // ignoring the contents of strings and comments.
130
+ function balanced(src, strings) {
131
+ const at = scannerAt(src, strings)
132
+ const stack = []
133
+ let i = 0
134
+ while (i < src.length) {
135
+ const s = at(i)
136
+ if (s > i) { if (s > src.length) return false; i = s; continue }
137
+ const c = src[i]
138
+ if (OPEN[c]) stack.push(c)
139
+ else if (CLOSE[c]) { if (stack.pop() !== CLOSE[c]) return false }
140
+ i++
141
+ }
142
+ return stack.length === 0
143
+ }
144
+
145
+ export function makeBraceLanguage({ id, exts, strings = ['"', "'", '`'] }) {
146
+ const provider = {
147
+ id,
148
+ exts,
149
+ parses: (src) => balanced(String(src == null ? '' : src), strings),
150
+ units: (src) => keyedUnits(topUnits(String(src), strings), String(src)),
151
+ declaredNames: (src) => {
152
+ const names = new Set()
153
+ for (const u of keyedUnits(topUnits(String(src), strings), String(src))) {
154
+ const m = u.key.match(/^(?:[a-z]+):([A-Za-z_$][\w$]*)/)
155
+ if (m && !u.key.startsWith('stmt:')) names.add(m[1])
156
+ }
157
+ return names
158
+ },
159
+ parsesUnit: (src) => balanced(String(src), strings),
160
+ // --- intent layer (heuristic but honest): dangling refs, rename, token merge ---
161
+ // Every identifier used in reference position (skips `.property` access). Approximate
162
+ // and OVER-inclusive — which only ever makes the dangling check MORE cautious: a
163
+ // deleted-but-still-referenced name is surfaced as a conflict, never shipped broken.
164
+ usedIdentifiers: (src) => {
165
+ src = String(src)
166
+ const used = new Set()
167
+ for (const t of lexTokens(src, strings)) if (isRefToken(src, t)) used.add(t.k)
168
+ return used
169
+ },
170
+ // The declaration's text with its own name excluded, so two declarations that differ
171
+ // only in their name compare equal — that's how the engine spots a rename.
172
+ declBody: (src, name) => {
173
+ src = String(src)
174
+ for (const u of keyedUnits(topUnits(src, strings), src)) {
175
+ const m = u.key.match(/^([a-z]+):(.+?)(?:#\d+)?$/)
176
+ if (!m || m[1] === 'stmt' || m[2] !== name) continue
177
+ return u.text.replace(name, '').trimEnd() // trailing whitespace must not defeat the rename match
178
+ }
179
+ return null
180
+ },
181
+ // Rewrite reference-position uses of oldName (never `.oldName` property access).
182
+ // Back-to-front so offsets stay valid. The engine only accepts the rewrite if the
183
+ // result still passes parses(), so a bad rewrite can't ship.
184
+ renameRefs: (src, oldName, newName) => {
185
+ src = String(src)
186
+ const spots = []
187
+ for (const t of lexTokens(src, strings)) if (t.k === oldName && isRefToken(src, t)) spots.push(t)
188
+ let out = src
189
+ for (const t of spots.reverse()) out = out.slice(0, t.start) + newName + out.slice(t.end)
190
+ return out
191
+ },
192
+ // Finest granularity: token stream for the engine's token-level inner merge.
193
+ tokenize: (src) => lexTokens(String(src), strings),
194
+ // Finer granularity: descend one level into a block declaration so two agents
195
+ // editing DIFFERENT members of the same class/function merge instead of clashing.
196
+ splitUnit: (text) => {
197
+ const src = String(text)
198
+ // Only descend into NAMED containers (class/struct/impl/…), whose members are
199
+ // keyed by name — so editing different members merges. A function/method body is
200
+ // just statements (no stable keys); descending there would falsely merge two
201
+ // edits to the same code, so we DON'T — the whole unit becomes a clean conflict.
202
+ if (!/\b(class|interface|struct|enum|trait|impl|namespace|module|object|record|extension|protocol|actor)\b/.test(src.split('{')[0]))
203
+ return null
204
+ const at = scannerAt(src, strings)
205
+ let i = 0, open = -1
206
+ while (i < src.length) { const s = at(i); if (s > i) { i = s; continue } if (src[i] === '{') { open = i; break } i++ }
207
+ if (open < 0) return null
208
+ // find matching close
209
+ let depth = 0, j = open, close = -1
210
+ while (j < src.length) { const s = at(j); if (s > j) { j = s; continue } const c = src[j]; if (c === '{') depth++; else if (c === '}') { depth--; if (depth === 0) { close = j; break } } j++ }
211
+ if (close < 0) return null
212
+ const sig = src.slice(0, open)
213
+ const body = src.slice(open + 1, close)
214
+ const inner = keyedUnits(topUnits(body, strings), body)
215
+ // inner ranges are already in `body` coordinates (topUnits scanned body). spliceable:
216
+ // the engine rebuilds the body by splicing merged members back into it, so the class's
217
+ // original indentation and any comments between members survive (no brace-glue reflow).
218
+ return { sig, open: '{', close: src.slice(close), body, units: inner, join: '\n', spliceable: true }
219
+ },
220
+ }
221
+ return provider
222
+ }
223
+
224
+ // Ready-made providers covering the common C-family languages. One provider can claim
225
+ // many extensions; comment/string syntax defaults fit the whole family (edge cases like
226
+ // Rust raw strings / lifetimes are tolerated — worst case a unit is merged coarsely).
227
+ export const braceLanguages = [
228
+ makeBraceLanguage({ id: 'ts', exts: ['.ts', '.tsx', '.mts', '.cts'] }),
229
+ makeBraceLanguage({ id: 'jsx', exts: ['.jsx'] }),
230
+ makeBraceLanguage({ id: 'go', exts: ['.go'], strings: ['"', '`'] }),
231
+ makeBraceLanguage({ id: 'rust', exts: ['.rs'] }),
232
+ makeBraceLanguage({ id: 'java', exts: ['.java'] }),
233
+ makeBraceLanguage({ id: 'c', exts: ['.c', '.h', '.cpp', '.hpp', '.cc', '.hh', '.cxx'] }),
234
+ makeBraceLanguage({ id: 'csharp', exts: ['.cs'] }),
235
+ makeBraceLanguage({ id: 'swift', exts: ['.swift'] }),
236
+ makeBraceLanguage({ id: 'kotlin', exts: ['.kt', '.kts'] }),
237
+ makeBraceLanguage({ id: 'scala', exts: ['.scala'] }),
238
+ makeBraceLanguage({ id: 'php', exts: ['.php'] }),
239
+ makeBraceLanguage({ id: 'dart', exts: ['.dart'] }),
240
+ ]