release: WRNexusJS 0.8.0
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env bun
|
||||
#!/usr/bin/env node
|
||||
// WRN editor language server source hash: 5397c7912894dd5ab330f6fafc0f4093adbb94d95c23366ba7883605a724a7ae
|
||||
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
|
||||
// @bun @bun-cjs
|
||||
(function(exports, require, module, __filename, __dirname) {var __create = Object.create;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
@@ -169438,6 +169440,17 @@ function formatOpeningTag(value, unit, depth, printWidth = 100, multilineAttribu
|
||||
opensElement
|
||||
};
|
||||
}
|
||||
if (parsed.attributes.length === 0 && !parsed.selfClosing) {
|
||||
const lines2 = [`${baseIndent}<${parsed.tagName}>`];
|
||||
if (parsed.trailingClosing) {
|
||||
if (parsed.inlineContent)
|
||||
lines2.push(`${childIndent}${parsed.inlineContent}`);
|
||||
lines2.push(`${baseIndent}</${parsed.tagName}>`);
|
||||
} else if (parsed.remainder) {
|
||||
lines2.push(`${childIndent}${parsed.remainder}`);
|
||||
}
|
||||
return { lines: lines2, opensElement };
|
||||
}
|
||||
const lines = [
|
||||
`${baseIndent}<${parsed.tagName}`,
|
||||
...parsed.attributes.flatMap((attribute) => formatAttribute(attribute, childIndent, unit))
|
||||
@@ -169475,6 +169488,63 @@ function isMultilineOpeningTagStart(value) {
|
||||
function isClosingTag(value) {
|
||||
return /^<\/[A-Za-z][\w$:.-]*\s*>/.test(value);
|
||||
}
|
||||
function isBalancedInlineHtmlFragment(value) {
|
||||
if (!value.startsWith("<") || value.startsWith("</") || value.startsWith("<!--")) {
|
||||
return false;
|
||||
}
|
||||
const stack = [];
|
||||
let tagCount = 0;
|
||||
let rootCount = 0;
|
||||
let hasNestedElement = false;
|
||||
let hasOutsideText = false;
|
||||
let index = 0;
|
||||
while (index < value.length) {
|
||||
const tagStart = value.indexOf("<", index);
|
||||
if (tagStart === -1) {
|
||||
if (stack.length === 0 && value.slice(index).trim())
|
||||
hasOutsideText = true;
|
||||
break;
|
||||
}
|
||||
if (stack.length === 0 && value.slice(index, tagStart).trim())
|
||||
hasOutsideText = true;
|
||||
if (value.startsWith("<!--", tagStart)) {
|
||||
const commentEnd = value.indexOf("-->", tagStart + 4);
|
||||
if (commentEnd === -1)
|
||||
return false;
|
||||
index = commentEnd + 3;
|
||||
continue;
|
||||
}
|
||||
const relativeEnd = findOpeningTagEnd(value.slice(tagStart));
|
||||
if (relativeEnd === -1)
|
||||
return false;
|
||||
const tag = value.slice(tagStart, tagStart + relativeEnd + 1);
|
||||
const match = /^<\/?([A-Za-z][\w$:.-]*)[\s\S]*?>$/.exec(tag);
|
||||
if (!match) {
|
||||
index = tagStart + 1;
|
||||
continue;
|
||||
}
|
||||
tagCount += 1;
|
||||
const tagName = match[1];
|
||||
const normalizedName = /^[a-z]/.test(tagName) ? tagName.toLowerCase() : tagName;
|
||||
const closing = tag.startsWith("</");
|
||||
const selfClosing = /\/\s*>$/.test(tag);
|
||||
const voidElement = VOID_ELEMENTS.has(tagName.toLowerCase());
|
||||
if (closing) {
|
||||
if (stack.at(-1) !== normalizedName)
|
||||
return false;
|
||||
stack.pop();
|
||||
} else {
|
||||
if (stack.length === 0)
|
||||
rootCount += 1;
|
||||
else
|
||||
hasNestedElement = true;
|
||||
if (!selfClosing && !voidElement)
|
||||
stack.push(normalizedName);
|
||||
}
|
||||
index = tagStart + relativeEnd + 1;
|
||||
}
|
||||
return tagCount >= 2 && stack.length === 0 && (rootCount > 1 || hasNestedElement || hasOutsideText);
|
||||
}
|
||||
function isControlBlockOpen(value) {
|
||||
return /^\{#(?:if|each)\b[\s\S]*\}$/.test(value);
|
||||
}
|
||||
@@ -169570,9 +169640,43 @@ function collectOpeningTag(inputLines, startIndex) {
|
||||
endIndex: index
|
||||
};
|
||||
}
|
||||
function isPreservedRawBlockStart(value) {
|
||||
return /<pre(?:\s|>)/i.test(value) && !/<\/pre\s*>/i.test(value.slice(0, value.search(/<pre(?:\s|>)/i)));
|
||||
}
|
||||
function hasPreservedRawBlockEnd(value) {
|
||||
return /<\/pre\s*>/i.test(value);
|
||||
}
|
||||
function transformOutsidePreservedRawBlocks(lines, transformLine) {
|
||||
const output = [];
|
||||
let preserving = false;
|
||||
for (const line of lines) {
|
||||
if (preserving) {
|
||||
output.push(line);
|
||||
if (hasPreservedRawBlockEnd(line))
|
||||
preserving = false;
|
||||
continue;
|
||||
}
|
||||
if (isPreservedRawBlockStart(line)) {
|
||||
output.push(line);
|
||||
preserving = !hasPreservedRawBlockEnd(line);
|
||||
continue;
|
||||
}
|
||||
output.push(...transformLine(line));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
function collectPreservedRawBlock(lines, startIndex) {
|
||||
const collected = [lines[startIndex]];
|
||||
let index = startIndex;
|
||||
while (!hasPreservedRawBlockEnd(collected.at(-1) || "") && index + 1 < lines.length) {
|
||||
index += 1;
|
||||
collected.push(lines[index]);
|
||||
}
|
||||
return { lines: collected, endIndex: index };
|
||||
}
|
||||
function expandInlineControlBlocks(lines) {
|
||||
const marker = /(\{#(?:if|each)\b[^}]*\}|\{:(?:else(?:\s+if\b[^}]*)?|empty)\}|\{\/(?:if|each)\})/g;
|
||||
return lines.flatMap((line) => {
|
||||
return transformOutsidePreservedRawBlocks(lines, (line) => {
|
||||
if (!marker.test(line))
|
||||
return [line];
|
||||
marker.lastIndex = 0;
|
||||
@@ -169582,7 +169686,7 @@ function expandInlineControlBlocks(lines) {
|
||||
});
|
||||
}
|
||||
function expandStructuredStateDeclarations(lines, unit) {
|
||||
return lines.flatMap((line) => {
|
||||
return transformOutsidePreservedRawBlocks(lines, (line) => {
|
||||
const match = /^(\s*state\s+[A-Za-z_$][\w$]*\s*=\s*)([\\[{][\s\S]*)$/.exec(line);
|
||||
if (!match)
|
||||
return [line];
|
||||
@@ -169638,6 +169742,14 @@ function formatWrnPass(source, options = {}) {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
if (isPreservedRawBlockStart(value)) {
|
||||
const collected = collectPreservedRawBlock(inputLines, index);
|
||||
const depth2 = codeDepth + htmlDepth + controlDepth;
|
||||
output.push(`${unit.repeat(depth2)}${collected.lines[0].trimStart()}`);
|
||||
output.push(...collected.lines.slice(1));
|
||||
index = collected.endIndex + 1;
|
||||
continue;
|
||||
}
|
||||
if (isMultilineOpeningTagStart(value)) {
|
||||
const collected = collectOpeningTag(inputLines, index);
|
||||
value = collected.value;
|
||||
@@ -169660,7 +169772,10 @@ function formatWrnPass(source, options = {}) {
|
||||
lineHtmlDepth = Math.max(0, htmlDepth - 1);
|
||||
}
|
||||
const depth = lineCodeDepth + lineHtmlDepth + lineControlDepth;
|
||||
if (value.startsWith("<") && !value.startsWith("</") && !value.startsWith("<!--") && !value.startsWith("<!") && !value.startsWith("<?")) {
|
||||
const inlineFragmentFits = unit.repeat(depth).length + value.length <= printWidth;
|
||||
if (isBalancedInlineHtmlFragment(value) && inlineFragmentFits) {
|
||||
output.push(`${unit.repeat(depth)}${value}`);
|
||||
} else if (value.startsWith("<") && !value.startsWith("</") && !value.startsWith("<!--") && !value.startsWith("<!") && !value.startsWith("<?")) {
|
||||
const formattedTag = formatOpeningTag(value, unit, depth, printWidth, multilineAttributes);
|
||||
output.push(...formattedTag.lines);
|
||||
if (formattedTag.opensElement) {
|
||||
@@ -169745,11 +169860,13 @@ function runtimeTypeOf(annotation) {
|
||||
if (!annotation)
|
||||
return "unknown";
|
||||
const type = annotation.trim().replace(/^readonly\s+/, "");
|
||||
if (/^(?:string|String)(?:\s*\|\s*(?:null|undefined))*$/.test(type))
|
||||
const unionParts = type.split("|").map((part) => part.trim());
|
||||
const concreteParts = unionParts.filter((part) => !/^(?:null|undefined)$/.test(part));
|
||||
if (/^(?:string|String)(?:\s*\|\s*(?:null|undefined))*$/.test(type) || concreteParts.length > 0 && concreteParts.every((part) => /^(?:"[^"]*"|'[^']*')$/.test(part)))
|
||||
return "string";
|
||||
if (/^(?:number|Number)(?:\s*\|\s*(?:null|undefined))*$/.test(type))
|
||||
if (/^(?:number|Number)(?:\s*\|\s*(?:null|undefined))*$/.test(type) || concreteParts.length > 0 && concreteParts.every((part) => /^-?(?:\d+\.?\d*|\.\d+)$/.test(part)))
|
||||
return "number";
|
||||
if (/^(?:boolean|Boolean)(?:\s*\|\s*(?:null|undefined))*$/.test(type))
|
||||
if (/^(?:boolean|Boolean)(?:\s*\|\s*(?:null|undefined))*$/.test(type) || concreteParts.length > 0 && concreteParts.every((part) => /^(?:true|false)$/.test(part)))
|
||||
return "boolean";
|
||||
if (/^bigint(?:\s*\|\s*(?:null|undefined))*$/.test(type))
|
||||
return "bigint";
|
||||
@@ -171689,7 +171806,7 @@ function runtimeNamespace(runtime) {
|
||||
return `__wrn_${runtime}`;
|
||||
}
|
||||
function functionDeclaration(fn) {
|
||||
const params = fn.parameters.map((param) => `${param.name}${param.optional ? "?" : ""}${param.valueType ? `: ${param.valueType}` : param.name === "event" ? ": CustomEvent<any> & { target: HTMLElement }" : ": unknown"}${param.default ? ` = ${param.default}` : ""}`).join(", ");
|
||||
const params = fn.parameters.map((param) => `${param.name}${param.optional ? "?" : ""}${param.valueType ? `: ${param.valueType}` : param.name === "event" ? ": CustomEvent<any> & { target: HTMLElement }" : ": any"}${param.default ? ` = ${param.default}` : ""}`).join(", ");
|
||||
return `export ${fn.async ? "async " : ""}function ${fn.name}(${params})${fn.returnType ? `: ${fn.returnType}` : ""} {${fn.body}}`;
|
||||
}
|
||||
function retainedImports(ast) {
|
||||
@@ -171702,6 +171819,51 @@ function retainedImports(ast) {
|
||||
}).map((entry) => entry.raw).join(`
|
||||
`);
|
||||
}
|
||||
var RESERVED_BINDING_NAMES = new Set([
|
||||
"await",
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"enum",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"let",
|
||||
"new",
|
||||
"null",
|
||||
"return",
|
||||
"static",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"yield"
|
||||
]);
|
||||
function safeBindingName(name) {
|
||||
return /^[A-Za-z_$][\w$]*$/.test(name) && !RESERVED_BINDING_NAMES.has(name);
|
||||
}
|
||||
function virtualTypeScriptModule(source, filePath = "component.wrn", appRoot = findAppRoot(filePath)) {
|
||||
const ast = parse(source);
|
||||
const chunks = [];
|
||||
@@ -171728,6 +171890,8 @@ function virtualTypeScriptModule(source, filePath = "component.wrn", appRoot = f
|
||||
|
||||
`), ast.types[0]?.trim());
|
||||
for (const prop of ast.props) {
|
||||
if (!safeBindingName(prop.name))
|
||||
continue;
|
||||
append(`declare const ${prop.name}: Readonly<${prop.valueType ?? "unknown"}>;`, prop.name);
|
||||
}
|
||||
for (const state of ast.states) {
|
||||
@@ -171739,7 +171903,7 @@ function virtualTypeScriptModule(source, filePath = "component.wrn", appRoot = f
|
||||
const outputType = ast.outputs.map((output) => `${output.name}: (${output.payload ? `${output.payload.name}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}) => void`).join("; ");
|
||||
const serverFunctions = ast.runtimeFunctions.filter((fn) => fn.runtime === "server");
|
||||
const serverType = serverFunctions.map((fn) => `${fn.name}: (${fn.parameters.map((param) => `${param.name}${param.optional ? "?" : ""}: ${param.valueType ?? "unknown"}`).join(", ")}) => ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")}`).join("; ");
|
||||
append(`declare const output: { ${outputType} };`);
|
||||
append(`declare const output: { [name: string]: (...args: any[]) => void; ${outputType} };`);
|
||||
for (const output of ast.outputs)
|
||||
append(`declare const ${output.name}: (${output.payload ? `${output.payload.name}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}) => void;`);
|
||||
for (const match of source.matchAll(/@event\s+([A-Za-z_$][\w$]*)\s*=\s*function/g))
|
||||
@@ -171923,7 +172087,8 @@ function componentUsageDiagnostics(source, ast, filePath, appRoot) {
|
||||
continue;
|
||||
const received = attr.boolean ? "boolean" : inferredRuntimeType(JSON.stringify(attr.value));
|
||||
const expected = runtimeTypeOf(prop.type);
|
||||
if (expected !== "unknown" && received !== "unknown" && expected !== received) {
|
||||
const compatibleLiteral = expected === "boolean" && /^(?:true|false|1|0|yes|no|on|off)?$/i.test(attr.value) || expected === "number" && attr.value.trim() !== "" && Number.isFinite(Number(attr.value));
|
||||
if (expected !== "unknown" && received !== "unknown" && expected !== received && !compatibleLiteral) {
|
||||
diagnostics.push({
|
||||
code: "WRN-COMPONENT-PROP-TYPE",
|
||||
category: "error",
|
||||
@@ -171956,8 +172121,12 @@ function componentUsageDiagnostics(source, ast, filePath, appRoot) {
|
||||
function category(value) {
|
||||
return value === import_typescript.default.DiagnosticCategory.Error ? "error" : value === import_typescript.default.DiagnosticCategory.Warning ? "warning" : "info";
|
||||
}
|
||||
function hostWithVirtualFiles(files, options) {
|
||||
function hostWithVirtualFiles(files, options, standardLibraryDirectory) {
|
||||
const host = import_typescript.default.createCompilerHost(options, true);
|
||||
if (standardLibraryDirectory) {
|
||||
host.getDefaultLibFileName = (compilerOptions) => import_node_path2.join(standardLibraryDirectory, import_typescript.default.getDefaultLibFileName(compilerOptions));
|
||||
host.getDefaultLibLocation = () => standardLibraryDirectory;
|
||||
}
|
||||
const originalGet = host.getSourceFile.bind(host);
|
||||
host.fileExists = (fileName) => files.has(import_node_path2.normalize(fileName)) || import_typescript.default.sys.fileExists(fileName);
|
||||
host.readFile = (fileName) => files.get(import_node_path2.normalize(fileName)) ?? import_typescript.default.sys.readFile(fileName);
|
||||
@@ -171967,10 +172136,23 @@ function hostWithVirtualFiles(files, options) {
|
||||
};
|
||||
return host;
|
||||
}
|
||||
function resolveStandardLibraryDirectory(appRoot, options) {
|
||||
const candidates = [
|
||||
import_node_path2.dirname(import_typescript.default.getDefaultLibFilePath(options)),
|
||||
import_node_path2.join(appRoot, "node_modules", "typescript", "lib"),
|
||||
import_node_path2.join(process.cwd(), "node_modules", "typescript", "lib")
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if ((options.lib ?? []).every((name) => import_typescript.default.sys.fileExists(import_node_path2.join(candidate, name)))) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function mappedPosition(virtual, line, column) {
|
||||
const mapping = virtual.mappings.find((entry) => line >= entry.virtualStartLine && line <= entry.virtualEndLine);
|
||||
if (!mapping)
|
||||
return { line: 1, column: 1 };
|
||||
return null;
|
||||
const offset = line - mapping.virtualStartLine;
|
||||
return {
|
||||
line: mapping.sourceStartLine + offset,
|
||||
@@ -172099,25 +172281,37 @@ function checkWrnSource(source, options = {}) {
|
||||
lib: ["lib.esnext.d.ts", "lib.dom.d.ts", "lib.dom.iterable.d.ts"]
|
||||
};
|
||||
const rootNames = [virtual.fileName, ...appTypes.files.keys()];
|
||||
const program = import_typescript.default.createProgram(rootNames, compilerOptions, hostWithVirtualFiles(files, compilerOptions));
|
||||
const tsDiagnostics = import_typescript.default.getPreEmitDiagnostics(program).map((diagnostic) => {
|
||||
const file = diagnostic.file;
|
||||
const start = diagnostic.start ?? 0;
|
||||
const virtualPosition = file?.getLineAndCharacterOfPosition(start) ?? { line: 0, character: 0 };
|
||||
const isVirtual = import_node_path2.normalize(file?.fileName ?? "") === import_node_path2.normalize(virtual.fileName);
|
||||
const sourcePosition = isVirtual ? mappedPosition(virtual, virtualPosition.line + 1, virtualPosition.character + 1) : { line: virtualPosition.line + 1, column: virtualPosition.character + 1 };
|
||||
return {
|
||||
code: `WRN-TYPE-${diagnostic.code}`,
|
||||
category: category(diagnostic.category),
|
||||
message: import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, `
|
||||
const standardLibraryDirectory = resolveStandardLibraryDirectory(appRoot, compilerOptions);
|
||||
const tsDiagnostics = [];
|
||||
if (standardLibraryDirectory) {
|
||||
const program = import_typescript.default.createProgram(rootNames, compilerOptions, hostWithVirtualFiles(files, compilerOptions, standardLibraryDirectory));
|
||||
for (const diagnostic of import_typescript.default.getPreEmitDiagnostics(program)) {
|
||||
const file = diagnostic.file;
|
||||
if (!file)
|
||||
continue;
|
||||
const normalizedFile = import_node_path2.normalize(file.fileName);
|
||||
const isVirtual = normalizedFile === import_node_path2.normalize(virtual.fileName);
|
||||
const isApplicationType = files.has(normalizedFile);
|
||||
if (!isVirtual && !isApplicationType)
|
||||
continue;
|
||||
const start = diagnostic.start ?? 0;
|
||||
const virtualPosition = file.getLineAndCharacterOfPosition(start);
|
||||
const sourcePosition = isVirtual ? mappedPosition(virtual, virtualPosition.line + 1, virtualPosition.character + 1) : { line: virtualPosition.line + 1, column: virtualPosition.character + 1 };
|
||||
if (!sourcePosition)
|
||||
continue;
|
||||
tsDiagnostics.push({
|
||||
code: `WRN-TYPE-${diagnostic.code}`,
|
||||
category: category(diagnostic.category),
|
||||
message: import_typescript.default.flattenDiagnosticMessageText(diagnostic.messageText, `
|
||||
`),
|
||||
file: isVirtual ? filePath : file?.fileName ?? filePath,
|
||||
line: sourcePosition.line,
|
||||
column: sourcePosition.column,
|
||||
length: diagnostic.length ?? 1,
|
||||
hint: "Fix the TypeScript contract or expression in the related .wrn declaration."
|
||||
};
|
||||
});
|
||||
file: isVirtual ? filePath : file.fileName,
|
||||
line: sourcePosition.line,
|
||||
column: sourcePosition.column,
|
||||
length: diagnostic.length ?? 1,
|
||||
hint: "Fix the TypeScript contract or expression in the related .wrn declaration."
|
||||
});
|
||||
}
|
||||
}
|
||||
return [
|
||||
...options.checkRuntimeBoundaries === false ? [] : runtimeDiagnostics(source, virtual.ast, filePath),
|
||||
...componentUsageDiagnostics(source, virtual.ast, filePath, appRoot),
|
||||
@@ -172527,11 +172721,30 @@ function send(value) {
|
||||
function result(id, value) {
|
||||
send({ jsonrpc: "2.0", id, result: value });
|
||||
}
|
||||
function internalDiagnostic(document, error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } },
|
||||
severity: 1,
|
||||
code: "WRN-LSP-INTERNAL",
|
||||
source: "wrnexus",
|
||||
message: `WRNexus language analysis failed safely: ${message}`
|
||||
};
|
||||
}
|
||||
function safeDocumentDiagnostics(document) {
|
||||
try {
|
||||
return documentDiagnostics(document);
|
||||
} catch (error) {
|
||||
process.stderr.write(`[wrnexus-lsp] diagnostics failed for ${document.uri}: ${error instanceof Error ? error.stack ?? error.message : String(error)}
|
||||
`);
|
||||
return [internalDiagnostic(document, error)];
|
||||
}
|
||||
}
|
||||
function publish(document) {
|
||||
send({
|
||||
jsonrpc: "2.0",
|
||||
method: "textDocument/publishDiagnostics",
|
||||
params: { uri: document.uri, diagnostics: documentDiagnostics(document) }
|
||||
params: { uri: document.uri, diagnostics: safeDocumentDiagnostics(document) }
|
||||
});
|
||||
}
|
||||
function clearDiagnosticTimer(uri) {
|
||||
@@ -172567,7 +172780,7 @@ async function handle(message) {
|
||||
case "initialize":
|
||||
workspaceRoot = params.rootPath ?? rootFromUri(params.rootUri);
|
||||
result(message.id, {
|
||||
serverInfo: { name: "WRNexus Language Server", version: "0.8.0" },
|
||||
serverInfo: { name: "WRNexus Language Server", version: "0.8.3" },
|
||||
capabilities: {
|
||||
textDocumentSync: 1,
|
||||
documentFormattingProvider: true,
|
||||
@@ -172676,7 +172889,7 @@ async function handle(message) {
|
||||
result(message.id, []);
|
||||
break;
|
||||
}
|
||||
const actions = documentDiagnostics(document).filter((item) => item.code === "WRNA11Y001").map((item) => ({
|
||||
const actions = safeDocumentDiagnostics(document).filter((item) => item.code === "WRNA11Y001").map((item) => ({
|
||||
title: "Add empty alt attribute",
|
||||
kind: "quickfix",
|
||||
diagnostics: [item],
|
||||
@@ -172740,12 +172953,36 @@ function consume() {
|
||||
return;
|
||||
const body = buffer.subarray(bodyStart, bodyStart + length).toString();
|
||||
buffer = buffer.subarray(bodyStart + length);
|
||||
handle(JSON.parse(body));
|
||||
let message;
|
||||
try {
|
||||
message = JSON.parse(body);
|
||||
} catch (error) {
|
||||
process.stderr.write(`[wrnexus-lsp] invalid JSON-RPC payload: ${error instanceof Error ? error.message : String(error)}
|
||||
`);
|
||||
continue;
|
||||
}
|
||||
handle(message).catch((error) => {
|
||||
const detail = error instanceof Error ? error.stack ?? error.message : String(error);
|
||||
process.stderr.write(`[wrnexus-lsp] request failed: ${detail}
|
||||
`);
|
||||
if (message.id !== undefined) {
|
||||
send({
|
||||
jsonrpc: "2.0",
|
||||
id: message.id,
|
||||
error: { code: -32603, message: "WRNexus language server request failed", data: detail }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
process.stdin.on("data", (chunk) => {
|
||||
buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
|
||||
consume();
|
||||
try {
|
||||
buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
|
||||
consume();
|
||||
} catch (error) {
|
||||
process.stderr.write(`[wrnexus-lsp] input processing failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}
|
||||
`);
|
||||
}
|
||||
});
|
||||
process.stdin.resume();
|
||||
})
|
||||
})(exports, require, module, __filename, __dirname);
|
||||
|
||||
Reference in New Issue
Block a user