release: WRNexusJS 0.2.29
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"name": "wrnexus",
|
||||
"displayName": "WRNexus Language Support",
|
||||
"description": "Syntax highlighting, formatting, diagnostics, snippets and completions for WrNexus .wrn files.",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.6",
|
||||
"publisher": "wrnexus",
|
||||
"private": true,
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
|
||||
const vscode = require("vscode");
|
||||
|
||||
const COMPONENT_DECLARATION =
|
||||
/^\s*(component|layout)\s+([A-Za-z_$][\w$]*)\s*\{/gm;
|
||||
const COMPONENT_DECLARATION = /^\s*(component|layout)\s+([A-Za-z_$][\w$]*)\s*\{/gm;
|
||||
|
||||
function getTagAtPosition(document, position) {
|
||||
const range = document.getWordRangeAtPosition(
|
||||
position,
|
||||
/[A-Za-z_$][\w$]*/,
|
||||
);
|
||||
const range = document.getWordRangeAtPosition(position, /[A-Za-z_$][\w$]*/);
|
||||
|
||||
if (!range) {
|
||||
return null;
|
||||
@@ -23,17 +19,13 @@ function getTagAtPosition(document, position) {
|
||||
|
||||
const line = document.lineAt(position.line).text;
|
||||
const offset = document.offsetAt(position);
|
||||
const lineStart = document.offsetAt(
|
||||
new vscode.Position(position.line, 0),
|
||||
);
|
||||
const lineStart = document.offsetAt(new vscode.Position(position.line, 0));
|
||||
|
||||
const characterOffset = offset - lineStart;
|
||||
const before = line.slice(0, characterOffset);
|
||||
const after = line.slice(characterOffset);
|
||||
|
||||
const insideTag =
|
||||
before.lastIndexOf("<") > before.lastIndexOf(">") &&
|
||||
after.includes(">");
|
||||
const insideTag = before.lastIndexOf("<") > before.lastIndexOf(">") && after.includes(">");
|
||||
|
||||
if (!insideTag) {
|
||||
return null;
|
||||
@@ -75,21 +67,12 @@ async function findDeclaration(name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const nameOffset =
|
||||
match.index +
|
||||
match[0].indexOf(declarationName);
|
||||
const nameOffset = match.index + match[0].indexOf(declarationName);
|
||||
|
||||
const start = document.positionAt(nameOffset);
|
||||
const end = document.positionAt(
|
||||
nameOffset + declarationName.length,
|
||||
);
|
||||
const end = document.positionAt(nameOffset + declarationName.length);
|
||||
|
||||
matches.push(
|
||||
new vscode.Location(
|
||||
uri,
|
||||
new vscode.Range(start, end),
|
||||
),
|
||||
);
|
||||
matches.push(new vscode.Location(uri, new vscode.Range(start, end)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +114,4 @@ module.exports = {
|
||||
getTagAtPosition,
|
||||
provideDefinition,
|
||||
registerDefinitionProvider,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,14 +5,9 @@ const vscode = require("vscode");
|
||||
const COLLECTION_NAME = "wrnexus";
|
||||
const WRN_LANGUAGE_ID = "wrn";
|
||||
|
||||
const TOP_LEVEL_PATTERN =
|
||||
/^\s*(page|component|layout)\s+([A-Za-z_$][\w$]*)\s*\{/;
|
||||
const TOP_LEVEL_PATTERN = /^\s*(page|component|layout)\s+([A-Za-z_$][\w$]*)\s*\{/;
|
||||
|
||||
const VALID_TOP_LEVEL_KINDS = new Set([
|
||||
"page",
|
||||
"component",
|
||||
"layout",
|
||||
]);
|
||||
const VALID_TOP_LEVEL_KINDS = new Set(["page", "component", "layout"]);
|
||||
|
||||
const VALID_MEMBERS = {
|
||||
page: new Set([
|
||||
@@ -28,21 +23,9 @@ const VALID_MEMBERS = {
|
||||
"realtime",
|
||||
]),
|
||||
|
||||
component: new Set([
|
||||
"props",
|
||||
"state",
|
||||
"view",
|
||||
"style",
|
||||
"functions",
|
||||
]),
|
||||
component: new Set(["props", "state", "view", "style", "functions"]),
|
||||
|
||||
layout: new Set([
|
||||
"props",
|
||||
"state",
|
||||
"view",
|
||||
"style",
|
||||
"functions",
|
||||
]),
|
||||
layout: new Set(["props", "state", "view", "style", "functions"]),
|
||||
};
|
||||
|
||||
function createDiagnostic(
|
||||
@@ -54,10 +37,7 @@ function createDiagnostic(
|
||||
code,
|
||||
) {
|
||||
const diagnostic = new vscode.Diagnostic(
|
||||
new vscode.Range(
|
||||
document.positionAt(startOffset),
|
||||
document.positionAt(endOffset),
|
||||
),
|
||||
new vscode.Range(document.positionAt(startOffset), document.positionAt(endOffset)),
|
||||
message,
|
||||
severity,
|
||||
);
|
||||
@@ -80,11 +60,7 @@ function lineDiagnostic(
|
||||
) {
|
||||
const line = document.lineAt(lineNumber);
|
||||
|
||||
const diagnostic = new vscode.Diagnostic(
|
||||
line.range,
|
||||
message,
|
||||
severity,
|
||||
);
|
||||
const diagnostic = new vscode.Diagnostic(line.range, message, severity);
|
||||
|
||||
diagnostic.source = "WRNexus";
|
||||
|
||||
@@ -96,18 +72,14 @@ function lineDiagnostic(
|
||||
}
|
||||
|
||||
function stripComments(source) {
|
||||
return source.replace(/<!--[\s\S]*?-->/g, (comment) =>
|
||||
comment.replace(/[^\n]/g, " "),
|
||||
);
|
||||
return source.replace(/<!--[\s\S]*?-->/g, (comment) => comment.replace(/[^\n]/g, " "));
|
||||
}
|
||||
|
||||
function findTopLevelDeclaration(document, source) {
|
||||
const match = TOP_LEVEL_PATTERN.exec(source);
|
||||
|
||||
if (!match) {
|
||||
const firstMeaningfulLine = source
|
||||
.split(/\r?\n/)
|
||||
.findIndex((line) => line.trim().length > 0);
|
||||
const firstMeaningfulLine = source.split(/\r?\n/).findIndex((line) => line.trim().length > 0);
|
||||
|
||||
return {
|
||||
diagnostic: lineDiagnostic(
|
||||
@@ -166,9 +138,7 @@ function validateBalancedCharacters(document, source) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
source.startsWith("<!--", index)
|
||||
) {
|
||||
if (source.startsWith("<!--", index)) {
|
||||
const commentEnd = source.indexOf("-->", index + 4);
|
||||
|
||||
if (commentEnd === -1) {
|
||||
@@ -190,11 +160,7 @@ function validateBalancedCharacters(document, source) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
character === "{" ||
|
||||
character === "[" ||
|
||||
character === "("
|
||||
) {
|
||||
if (character === "{" || character === "[" || character === "(") {
|
||||
stack.push({
|
||||
character,
|
||||
offset: index,
|
||||
@@ -203,11 +169,7 @@ function validateBalancedCharacters(document, source) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
character === "}" ||
|
||||
character === "]" ||
|
||||
character === ")"
|
||||
) {
|
||||
if (character === "}" || character === "]" || character === ")") {
|
||||
const expectedOpening = pairs[character];
|
||||
const opening = stack.pop();
|
||||
|
||||
@@ -227,12 +189,7 @@ function validateBalancedCharacters(document, source) {
|
||||
}
|
||||
|
||||
for (const opening of stack) {
|
||||
const expectedClosing =
|
||||
opening.character === "{"
|
||||
? "}"
|
||||
: opening.character === "["
|
||||
? "]"
|
||||
: ")";
|
||||
const expectedClosing = opening.character === "{" ? "}" : opening.character === "[" ? "]" : ")";
|
||||
|
||||
diagnostics.push(
|
||||
createDiagnostic(
|
||||
@@ -284,8 +241,7 @@ function validateHtmlTags(document, source) {
|
||||
]);
|
||||
|
||||
const cleaned = stripComments(source);
|
||||
const tagPattern =
|
||||
/<\/?([A-Za-z][A-Za-z0-9_$:.-]*)(?:\s[\s\S]*?)?\/?>/g;
|
||||
const tagPattern = /<\/?([A-Za-z][A-Za-z0-9_$:.-]*)(?:\s[\s\S]*?)?\/?>/g;
|
||||
|
||||
let match;
|
||||
|
||||
@@ -358,18 +314,13 @@ function validateHtmlTags(document, source) {
|
||||
}
|
||||
|
||||
function getRootBodyRange(source, rootMatch) {
|
||||
const openingBrace =
|
||||
rootMatch.index + rootMatch[0].lastIndexOf("{");
|
||||
const openingBrace = rootMatch.index + rootMatch[0].lastIndexOf("{");
|
||||
|
||||
let depth = 0;
|
||||
let quote = null;
|
||||
let escaped = false;
|
||||
|
||||
for (
|
||||
let index = openingBrace;
|
||||
index < source.length;
|
||||
index += 1
|
||||
) {
|
||||
for (let index = openingBrace; index < source.length; index += 1) {
|
||||
const character = source[index];
|
||||
|
||||
if (quote !== null) {
|
||||
@@ -425,6 +376,12 @@ function findRootMembers(source, bodyStart, bodyEnd) {
|
||||
let quote = null;
|
||||
let escaped = false;
|
||||
|
||||
const skipLine = () => {
|
||||
while (index < bodyEnd && source[index] !== "\n" && source[index] !== "\r") {
|
||||
index += 1;
|
||||
}
|
||||
};
|
||||
|
||||
while (index < bodyEnd) {
|
||||
const character = source[index];
|
||||
|
||||
@@ -473,17 +430,11 @@ function findRootMembers(source, bodyStart, bodyEnd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
depth === 0 &&
|
||||
/[A-Za-z_]/.test(character)
|
||||
) {
|
||||
if (depth === 0 && /[A-Za-z_]/.test(character)) {
|
||||
const start = index;
|
||||
index += 1;
|
||||
|
||||
while (
|
||||
index < bodyEnd &&
|
||||
/[A-Za-z0-9_-]/.test(source[index])
|
||||
) {
|
||||
while (index < bodyEnd && /[A-Za-z0-9_-]/.test(source[index])) {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
@@ -495,6 +446,11 @@ function findRootMembers(source, bodyStart, bodyEnd) {
|
||||
end: index,
|
||||
});
|
||||
|
||||
// Single-line declarations must skip the rest of the line.
|
||||
if (name === "state" || name === "layout") {
|
||||
skipLine();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -504,12 +460,7 @@ function findRootMembers(source, bodyStart, bodyEnd) {
|
||||
return members;
|
||||
}
|
||||
|
||||
function validateRootMembers(
|
||||
document,
|
||||
source,
|
||||
rootKind,
|
||||
rootMatch,
|
||||
) {
|
||||
function validateRootMembers(document, source, rootKind, rootMatch) {
|
||||
const diagnostics = [];
|
||||
const allowed = VALID_MEMBERS[rootKind];
|
||||
|
||||
@@ -518,11 +469,7 @@ function validateRootMembers(
|
||||
}
|
||||
|
||||
const bodyRange = getRootBodyRange(source, rootMatch);
|
||||
const members = findRootMembers(
|
||||
source,
|
||||
bodyRange.start,
|
||||
bodyRange.end,
|
||||
);
|
||||
const members = findRootMembers(source, bodyRange.start, bodyRange.end);
|
||||
|
||||
for (const member of members) {
|
||||
if (allowed.has(member.name)) {
|
||||
@@ -544,12 +491,7 @@ function validateRootMembers(
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
function validateRequiredView(
|
||||
document,
|
||||
source,
|
||||
rootKind,
|
||||
rootMatch,
|
||||
) {
|
||||
function validateRequiredView(document, source, rootKind, rootMatch) {
|
||||
const bodyRange = getRootBodyRange(source, rootMatch);
|
||||
const body = source.slice(bodyRange.start, bodyRange.end);
|
||||
|
||||
@@ -569,17 +511,10 @@ function validateRequiredView(
|
||||
];
|
||||
}
|
||||
|
||||
function validateLayoutUsage(
|
||||
document,
|
||||
source,
|
||||
rootKind,
|
||||
) {
|
||||
function validateLayoutUsage(document, source, rootKind) {
|
||||
const diagnostics = [];
|
||||
|
||||
if (
|
||||
rootKind !== "page" &&
|
||||
/^\s*layout\s*=/m.test(source)
|
||||
) {
|
||||
if (rootKind !== "page" && /^\s*layout\s*=/m.test(source)) {
|
||||
const match = /^\s*layout\s*=/m.exec(source);
|
||||
|
||||
if (match) {
|
||||
@@ -588,7 +523,7 @@ function validateLayoutUsage(
|
||||
document,
|
||||
match.index,
|
||||
match.index + match[0].length,
|
||||
"`layout = \"...\"` is only valid inside a page.",
|
||||
'`layout = "..."` is only valid inside a page.',
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
"wrn-invalid-layout-member",
|
||||
),
|
||||
@@ -611,16 +546,11 @@ function validateDocument(document) {
|
||||
}
|
||||
|
||||
const diagnostics = [];
|
||||
const declaration = findTopLevelDeclaration(
|
||||
document,
|
||||
source,
|
||||
);
|
||||
const declaration = findTopLevelDeclaration(document, source);
|
||||
|
||||
if (declaration.diagnostic) {
|
||||
diagnostics.push(declaration.diagnostic);
|
||||
diagnostics.push(
|
||||
...validateBalancedCharacters(document, source),
|
||||
);
|
||||
diagnostics.push(...validateBalancedCharacters(document, source));
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
@@ -630,8 +560,7 @@ function validateDocument(document) {
|
||||
createDiagnostic(
|
||||
document,
|
||||
declaration.match.index,
|
||||
declaration.match.index +
|
||||
declaration.match[0].length,
|
||||
declaration.match.index + declaration.match[0].length,
|
||||
`Unsupported WRN declaration \`${declaration.kind}\`.`,
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
"wrn-invalid-kind",
|
||||
@@ -641,48 +570,21 @@ function validateDocument(document) {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
diagnostics.push(
|
||||
...validateBalancedCharacters(document, source),
|
||||
);
|
||||
diagnostics.push(...validateBalancedCharacters(document, source));
|
||||
|
||||
diagnostics.push(
|
||||
...validateHtmlTags(document, source),
|
||||
);
|
||||
diagnostics.push(...validateHtmlTags(document, source));
|
||||
|
||||
diagnostics.push(
|
||||
...validateRootMembers(
|
||||
document,
|
||||
source,
|
||||
declaration.kind,
|
||||
declaration.match,
|
||||
),
|
||||
);
|
||||
diagnostics.push(...validateRootMembers(document, source, declaration.kind, declaration.match));
|
||||
|
||||
diagnostics.push(
|
||||
...validateRequiredView(
|
||||
document,
|
||||
source,
|
||||
declaration.kind,
|
||||
declaration.match,
|
||||
),
|
||||
);
|
||||
diagnostics.push(...validateRequiredView(document, source, declaration.kind, declaration.match));
|
||||
|
||||
diagnostics.push(
|
||||
...validateLayoutUsage(
|
||||
document,
|
||||
source,
|
||||
declaration.kind,
|
||||
),
|
||||
);
|
||||
diagnostics.push(...validateLayoutUsage(document, source, declaration.kind));
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
function registerDiagnostics(context) {
|
||||
const collection =
|
||||
vscode.languages.createDiagnosticCollection(
|
||||
COLLECTION_NAME,
|
||||
);
|
||||
const collection = vscode.languages.createDiagnosticCollection(COLLECTION_NAME);
|
||||
|
||||
const timers = new Map();
|
||||
|
||||
@@ -691,9 +593,7 @@ function registerDiagnostics(context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const previousTimer = timers.get(
|
||||
document.uri.toString(),
|
||||
);
|
||||
const previousTimer = timers.get(document.uri.toString());
|
||||
|
||||
if (previousTimer) {
|
||||
clearTimeout(previousTimer);
|
||||
@@ -702,10 +602,7 @@ function registerDiagnostics(context) {
|
||||
const timer = setTimeout(() => {
|
||||
timers.delete(document.uri.toString());
|
||||
|
||||
collection.set(
|
||||
document.uri,
|
||||
validateDocument(document),
|
||||
);
|
||||
collection.set(document.uri, validateDocument(document));
|
||||
}, 150);
|
||||
|
||||
timers.set(document.uri.toString(), timer);
|
||||
@@ -726,19 +623,17 @@ function registerDiagnostics(context) {
|
||||
|
||||
vscode.workspace.onDidSaveTextDocument(update),
|
||||
|
||||
vscode.workspace.onDidCloseTextDocument(
|
||||
(document) => {
|
||||
const key = document.uri.toString();
|
||||
const timer = timers.get(key);
|
||||
vscode.workspace.onDidCloseTextDocument((document) => {
|
||||
const key = document.uri.toString();
|
||||
const timer = timers.get(key);
|
||||
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timers.delete(key);
|
||||
}
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timers.delete(key);
|
||||
}
|
||||
|
||||
collection.delete(document.uri);
|
||||
},
|
||||
),
|
||||
collection.delete(document.uri);
|
||||
}),
|
||||
|
||||
{
|
||||
dispose() {
|
||||
@@ -758,4 +653,4 @@ module.exports = {
|
||||
validateDocument,
|
||||
validateHtmlTags,
|
||||
validateRootMembers,
|
||||
};
|
||||
};
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user