Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import { existsSync, readdirSync, readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { bundledPluginFile } from "../../../test/helpers/bundled-plugin-paths.js";
const thisFilePath = fileURLToPath(import.meta.url);
const thisDir = path.dirname(thisFilePath);
const repoRoot = path.resolve(thisDir, "../../..");
const loadConfigPattern = /\b(?:loadConfig|config\.loadConfig)\s*\(/;
function toPosix(relativePath: string): string {
return relativePath.split(path.sep).join("/");
}
function readRepoFile(relativePath: string): string {
const absolute = path.join(repoRoot, relativePath);
return readFileSync(absolute, "utf8");
}
function listCoreOutboundEntryFiles(): string[] {
const outboundDir = path.join(repoRoot, "src/channels/plugins/outbound");
return readdirSync(outboundDir)
.filter((name) => name.endsWith(".ts") && !name.endsWith(".test.ts"))
.map((name) => toPosix(path.join("src/channels/plugins/outbound", name)))
.toSorted();
}
function listExtensionFiles(): {
adapterEntrypoints: string[];
inlineChannelEntrypoints: string[];
} {
const extensionsRoot = path.join(repoRoot, "extensions");
const adapterEntrypoints: string[] = [];
const inlineChannelEntrypoints: string[] = [];
for (const entry of readdirSync(extensionsRoot, { withFileTypes: true })) {
if (!entry.isDirectory()) {
continue;
}
const srcDir = path.join(extensionsRoot, entry.name, "src");
const outboundPath = path.join(srcDir, "outbound.ts");
if (existsSync(outboundPath)) {
adapterEntrypoints.push(toPosix(path.join("extensions", entry.name, "src/outbound.ts")));
}
const channelPath = path.join(srcDir, "channel.ts");
if (!existsSync(channelPath)) {
continue;
}
const source = readFileSync(channelPath, "utf8");
if (/\boutbound\s*:\s*\{/.test(source)) {
inlineChannelEntrypoints.push(toPosix(path.join("extensions", entry.name, "src/channel.ts")));
}
}
return {
adapterEntrypoints: adapterEntrypoints.toSorted(),
inlineChannelEntrypoints: inlineChannelEntrypoints.toSorted(),
};
}
function listHighRiskRuntimeCfgFiles(): string[] {
return [
bundledPluginFile("telegram", "src/action-runtime.ts"),
bundledPluginFile("discord", "src/monitor/reply-delivery.ts"),
bundledPluginFile("discord", "src/monitor/thread-bindings.discord-api.ts"),
bundledPluginFile("discord", "src/monitor/thread-bindings.manager.ts"),
];
}
function extractOutboundBlock(source: string, file: string): string {
const outboundKeyIndex = source.indexOf("outbound:");
expect(outboundKeyIndex, `${file} should define outbound:`).toBeGreaterThanOrEqual(0);
const braceStart = source.indexOf("{", outboundKeyIndex);
expect(braceStart, `${file} should define outbound object`).toBeGreaterThanOrEqual(0);
let depth = 0;
let state: "code" | "single" | "double" | "template" | "lineComment" | "blockComment" = "code";
for (let i = braceStart; i < source.length; i += 1) {
const current = source[i];
const next = source[i + 1];
if (state === "lineComment") {
if (current === "\n") {
state = "code";
}
continue;
}
if (state === "blockComment") {
if (current === "*" && next === "/") {
state = "code";
i += 1;
}
continue;
}
if (state === "single") {
if (current === "\\" && next) {
i += 1;
continue;
}
if (current === "'") {
state = "code";
}
continue;
}
if (state === "double") {
if (current === "\\" && next) {
i += 1;
continue;
}
if (current === '"') {
state = "code";
}
continue;
}
if (state === "template") {
if (current === "\\" && next) {
i += 1;
continue;
}
if (current === "`") {
state = "code";
}
continue;
}
if (current === "/" && next === "/") {
state = "lineComment";
i += 1;
continue;
}
if (current === "/" && next === "*") {
state = "blockComment";
i += 1;
continue;
}
if (current === "'") {
state = "single";
continue;
}
if (current === '"') {
state = "double";
continue;
}
if (current === "`") {
state = "template";
continue;
}
if (current === "{") {
depth += 1;
continue;
}
if (current === "}") {
depth -= 1;
if (depth === 0) {
return source.slice(braceStart, i + 1);
}
}
}
throw new Error(`Unable to parse outbound block in ${file}`);
}
describe("outbound cfg-threading guard", () => {
it("keeps outbound adapter entrypoints free of loadConfig calls", () => {
const coreAdapterFiles = listCoreOutboundEntryFiles();
const extensionAdapterFiles = listExtensionFiles().adapterEntrypoints;
const adapterFiles = [...coreAdapterFiles, ...extensionAdapterFiles];
for (const file of adapterFiles) {
const source = readRepoFile(file);
expect(source, `${file} must not call loadConfig in outbound entrypoint`).not.toMatch(
loadConfigPattern,
);
}
});
it("keeps inline channel outbound blocks free of loadConfig calls", () => {
const inlineFiles = listExtensionFiles().inlineChannelEntrypoints;
for (const file of inlineFiles) {
const source = readRepoFile(file);
const outboundBlock = extractOutboundBlock(source, file);
expect(outboundBlock, `${file} outbound block must not call loadConfig`).not.toMatch(
loadConfigPattern,
);
}
});
it("keeps high-risk runtime delivery paths free of loadConfig calls", () => {
const runtimeFiles = listHighRiskRuntimeCfgFiles();
for (const file of runtimeFiles) {
const source = readRepoFile(file);
expect(source, `${file} must not call loadConfig`).not.toMatch(loadConfigPattern);
}
});
});
¤ Dauer der Verarbeitung: 0.41 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland