UNPKG

socraticode

Version:

SocratiCode — MCP server for local codebase indexing, semantic search, and code dependency graphs. All private, all local via Docker.

89 lines • 3.71 kB
// SPDX-License-Identifier: AGPL-3.0-only // Copyright (C) 2026 Giancarlo Erra - Altaire Limited const IDENTIFIER_START = /^[_\p{ID_Start}]$/u; const IDENTIFIER_CONTINUE = /^[_\p{ID_Continue}]$/u; /** Return one Unicode code point without splitting surrogate pairs. */ function codePointAt(source, index) { const codePoint = source.codePointAt(index); return codePoint === undefined ? "" : String.fromCodePoint(codePoint); } /** * Tokenize only the GDScript constructs needed by import and class-name fallbacks. * Comments and whitespace are discarded, while quoted strings remain single tokens. */ export function tokenizeGdscript(source) { const tokens = []; let index = 0; while (index < source.length) { const current = codePointAt(source, index); if (/^\s$/u.test(current)) { index += current.length; continue; } if (current === "#") { while (index < source.length && source[index] !== "\n" && source[index] !== "\r") { index++; } continue; } const rawPrefix = (current === "r" || current === "R") && (source[index + 1] === "\"" || source[index + 1] === "'"); const quoteIndex = rawPrefix ? index + 1 : index; const quote = source[quoteIndex]; if (quote === "\"" || quote === "'") { const start = index; const triple = source.slice(quoteIndex, quoteIndex + 3) === quote.repeat(3); const delimiterLength = triple ? 3 : 1; index = quoteIndex + delimiterLength; while (index < source.length) { // Raw strings still recognize an escaped matching quote (and `\\\\`). // Skip the escaped code point before checking for the closing delimiter // so `r"quoted: \\" text"` remains one string token. if (source[index] === "\\") { index += Math.min(2, source.length - index); continue; } if (source.slice(index, index + delimiterLength) === quote.repeat(delimiterLength)) { index += delimiterLength; break; } if (!triple && (source[index] === "\n" || source[index] === "\r")) break; index++; } tokens.push({ kind: "string", text: source.slice(start, index) }); continue; } if (IDENTIFIER_START.test(current)) { const start = index; index += current.length; while (index < source.length) { const next = codePointAt(source, index); if (!IDENTIFIER_CONTINUE.test(next)) break; index += next.length; } tokens.push({ kind: "identifier", text: source.slice(start, index) }); continue; } tokens.push({ kind: "punctuation", text: current }); index += current.length; } return tokens; } /** Find a real class_name declaration while ignoring comments and string bodies. */ export function extractClassNameFromGdscript(source) { const tokens = tokenizeGdscript(source); for (let index = 0; index < tokens.length - 1; index++) { const token = tokens[index]; if (token.kind !== "identifier" || token.text !== "class_name") continue; if (tokens[index - 1]?.text === ".") continue; const name = tokens[index + 1]; if (name?.kind === "identifier") return name.text; } return null; } //# sourceMappingURL=gdscript-syntax.js.map