release: WRNexusJS 0.2.27

This commit is contained in:
2026-07-14 14:40:13 +05:30
parent fef4218a07
commit d3094010af
64 changed files with 763 additions and 244 deletions
+203
View File
@@ -0,0 +1,203 @@
"use strict";
const vscode = require("vscode");
const BLOCK_COMPLETIONS = [
{
label: "page",
detail: "WRN page",
documentation: "Create a WRN page declaration.",
snippet: [
"page ${1:PageName} {",
' layout = "${2:default}"',
"",
" view {",
" $0",
" }",
"}",
].join("\n"),
},
{
label: "component",
detail: "WRN component",
documentation: "Create a reusable WRN component.",
snippet: [
"component ${1:ComponentName} {",
" props {",
' ${2:title} = "${3:Title}"',
" }",
"",
" view {",
" $0",
" }",
"}",
].join("\n"),
},
{
label: "seo",
detail: "SEO metadata block",
snippet: [
"seo {",
' title = "${1:Page title}"',
' description = "${2:Page description}"',
"}",
].join("\n"),
},
{
label: "view",
detail: "WRN view block",
snippet: ["view {", " $0", "}"].join("\n"),
},
{
label: "state",
detail: "Reactive state declaration",
snippet: 'state ${1:name} = ${2:"value"}',
},
];
const ATTRIBUTE_COMPLETIONS = [
["@click", "Click event handler", '@click="${1:handler()}"'],
["@change", "Change event handler", '@change="${1:handler()}"'],
["@input", "Input event handler", '@input="${1:handler()}"'],
["@submit", "Submit event handler", '@submit="${1:handler()}"'],
["@focus", "Focus event handler", '@focus="${1:handler()}"'],
["@blur", "Blur event handler", '@blur="${1:handler()}"'],
["data-show", "Conditional visibility", 'data-show="${1:condition}"'],
["data-for", "Reactive loop", 'data-for="${1:item} in ${2:items}"'],
["class:", "Conditional CSS class", 'class:${1:border-indigo-500}="${2:condition}"'],
];
const CONTEXT_COMPLETIONS = [
["ctx.params", "Dynamic route parameters"],
["ctx.query", "URL query parameters"],
["ctx.request", "Current Request object"],
["ctx.user", "Authenticated user"],
["ctx.session", "Current session"],
["ctx.locals", "Request-local data"],
];
function completionKindFor(label) {
if (label.startsWith("@")) {
return vscode.CompletionItemKind.Event;
}
if (label.startsWith("class:") || label.startsWith("data-")) {
return vscode.CompletionItemKind.Property;
}
return vscode.CompletionItemKind.Keyword;
}
function createCompletion(label, detail, snippet) {
const item = new vscode.CompletionItem(label, completionKindFor(label));
item.detail = detail;
item.insertText = new vscode.SnippetString(snippet || label);
item.documentation = new vscode.MarkdownString(detail);
return item;
}
function getCurrentOpeningTag(document, position) {
const textBeforeCursor = document.getText(
new vscode.Range(new vscode.Position(position.line, 0), position),
);
const lastOpen = textBeforeCursor.lastIndexOf("<");
const lastClose = textBeforeCursor.lastIndexOf(">");
if (lastOpen > lastClose) {
return textBeforeCursor.slice(lastOpen);
}
return null;
}
function extractRouteParams(document) {
const fileName = document.fileName.replace(/\\/g, "/");
const matches = [...fileName.matchAll(/\[([A-Za-z_$][\w$]*)\]/g)];
return matches.map((match) => match[1]);
}
function extractStates(document) {
const source = document.getText();
const matches = [...source.matchAll(/^\s*state\s+([A-Za-z_$][\w$]*)\s*=/gm)];
return matches.map((match) => match[1]);
}
function provideCompletionItems(document, position) {
const items = [];
const linePrefix = document.lineAt(position.line).text.slice(0, position.character);
const openingTag = getCurrentOpeningTag(document, position);
if (openingTag !== null) {
for (const [label, detail, snippet] of ATTRIBUTE_COMPLETIONS) {
items.push(createCompletion(label, detail, snippet));
}
} else {
for (const completion of BLOCK_COMPLETIONS) {
items.push(createCompletion(completion.label, completion.detail, completion.snippet));
}
}
if (linePrefix.includes("ctx.") || linePrefix.includes("ctx.params.")) {
for (const [label, detail] of CONTEXT_COMPLETIONS) {
items.push(createCompletion(label, detail, label));
}
}
for (const param of extractRouteParams(document)) {
const item = new vscode.CompletionItem(param, vscode.CompletionItemKind.Variable);
item.detail = `Route parameter from [${param}].wrn`;
item.insertText = param;
items.push(item);
const fullItem = new vscode.CompletionItem(
`ctx.params.${param}`,
vscode.CompletionItemKind.Variable,
);
fullItem.detail = `Route parameter from [${param}].wrn`;
fullItem.insertText = `ctx.params.${param}`;
items.push(fullItem);
}
for (const state of extractStates(document)) {
const item = new vscode.CompletionItem(state, vscode.CompletionItemKind.Variable);
item.detail = "WRN state";
item.insertText = state;
items.push(item);
}
return items;
}
function registerCompletionProvider(context) {
const provider = vscode.languages.registerCompletionItemProvider(
{ language: "wrn", scheme: "file" },
{
provideCompletionItems,
},
"@",
":",
".",
"<",
" ",
);
context.subscriptions.push(provider);
}
module.exports = {
extractRouteParams,
extractStates,
registerCompletionProvider,
};