release: WRNexusJS 0.3.0
This commit is contained in:
+2900
-1939
File diff suppressed because it is too large
Load Diff
@@ -106,6 +106,56 @@ const BLOCK_COMPLETIONS = [
|
||||
documentation: "Declare reactive state owned by the current component, layout, or page.",
|
||||
snippet: 'state ${1:name}: ${2:string} = ${3:"value"}',
|
||||
},
|
||||
{
|
||||
label: "runtime",
|
||||
detail: "WRN execution target",
|
||||
documentation: "Choose whether this declaration executes on the server, client, or both.",
|
||||
snippet: 'runtime = "${1|universal,server,client|}"',
|
||||
},
|
||||
{
|
||||
label: "hydrate",
|
||||
detail: "WRN hydration strategy",
|
||||
documentation: "Choose when client interactivity is initialized for this declaration.",
|
||||
snippet: 'hydrate = "${1|load,idle,visible,interaction,none|}"',
|
||||
},
|
||||
{
|
||||
label: "computed",
|
||||
detail: "Derived reactive values block",
|
||||
documentation:
|
||||
"Declare values that are recomputed only when their reactive dependencies change.",
|
||||
snippet: ["computed {", " ${1:displayName} = ${2:firstName + ' ' + lastName}", "}"].join(
|
||||
"\n",
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "effect",
|
||||
detail: "Reactive side-effect block",
|
||||
documentation: "Run browser-side code whenever its referenced reactive values change.",
|
||||
snippet: ["effect {", " ${1:console.log(value)}", "}"].join("\n"),
|
||||
},
|
||||
{
|
||||
label: "security",
|
||||
detail: "Route security metadata block",
|
||||
documentation: "Declare authentication, authorization, CSRF, and rate-limit policy metadata.",
|
||||
snippet: [
|
||||
"security {",
|
||||
' auth = "${1|required,optional,public|}"',
|
||||
' csrf = "${2:true}"',
|
||||
"}",
|
||||
].join("\n"),
|
||||
},
|
||||
{
|
||||
label: "load",
|
||||
detail: "Typed data-loading block",
|
||||
documentation: "Load data on the server or client with an explicit execution boundary.",
|
||||
snippet: ["load ${1|server,client|} {", " ${2:return {}}", "}"].join("\n"),
|
||||
},
|
||||
{
|
||||
label: "action",
|
||||
detail: "Named server action",
|
||||
documentation: "Declare a callable mutation with an explicit name and arguments.",
|
||||
snippet: ["action ${1:save}(${2:input}) {", " $0", "}"].join("\n"),
|
||||
},
|
||||
{
|
||||
label: "functions",
|
||||
detail: "Browser component functions block",
|
||||
@@ -215,6 +265,8 @@ const CONTEXT_COMPLETIONS = [
|
||||
["ctx.user", "Authenticated user"],
|
||||
["ctx.session", "Current session"],
|
||||
["ctx.locals", "Request-local data"],
|
||||
["ctx.tenant", "Resolved tenant context"],
|
||||
["ctx.tracer", "Request tracing interface"],
|
||||
];
|
||||
|
||||
const WATCH_VALUE_COMPLETIONS = [
|
||||
|
||||
@@ -11,33 +11,34 @@ const VALID_TOP_LEVEL_KINDS = new Set(["page", "component", "layout"]);
|
||||
|
||||
const VALID_LIFECYCLE_HOOKS = new Set(["mount", "update", "unmount"]);
|
||||
|
||||
const ROOT_MEMBER_NAMES = [
|
||||
"layout",
|
||||
"runtime",
|
||||
"hydrate",
|
||||
"client",
|
||||
"types",
|
||||
"props",
|
||||
"state",
|
||||
"computed",
|
||||
"effect",
|
||||
"watch",
|
||||
"lifecycle",
|
||||
"view",
|
||||
"seo",
|
||||
"security",
|
||||
"load",
|
||||
"action",
|
||||
"api",
|
||||
"ssr",
|
||||
"realtime",
|
||||
"style",
|
||||
"functions",
|
||||
];
|
||||
|
||||
const VALID_MEMBERS = {
|
||||
page: new Set([
|
||||
"layout",
|
||||
"state",
|
||||
"types",
|
||||
"view",
|
||||
"seo",
|
||||
"style",
|
||||
"functions",
|
||||
"api",
|
||||
"ssr",
|
||||
"client",
|
||||
"realtime",
|
||||
]),
|
||||
|
||||
component: new Set([
|
||||
"types",
|
||||
"props",
|
||||
"state",
|
||||
"view",
|
||||
"style",
|
||||
"functions",
|
||||
"lifecycle",
|
||||
"watch",
|
||||
]),
|
||||
|
||||
layout: new Set(["types", "props", "state", "view", "style", "functions", "lifecycle", "watch"]),
|
||||
page: new Set(ROOT_MEMBER_NAMES),
|
||||
component: new Set(ROOT_MEMBER_NAMES),
|
||||
layout: new Set(ROOT_MEMBER_NAMES),
|
||||
};
|
||||
|
||||
function createDiagnostic(
|
||||
@@ -544,21 +545,87 @@ function findRootMembers(source, bodyStart, bodyEnd) {
|
||||
end: identifier.end,
|
||||
});
|
||||
|
||||
if (identifier.name === "state" || identifier.name === "layout") {
|
||||
const assignmentMembers = new Set(["layout", "runtime", "hydrate", "state"]);
|
||||
|
||||
if (assignmentMembers.has(identifier.name)) {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (identifier.name === "watch") {
|
||||
index = skipWhitespace(source, index, bodyEnd);
|
||||
if (identifier.name === "client") {
|
||||
const next = skipWhitespace(source, index, bodyEnd);
|
||||
|
||||
const watchedState = readIdentifier(source, index, bodyEnd);
|
||||
|
||||
if (watchedState) {
|
||||
index = watchedState.end;
|
||||
if (source[next] === "=") {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const blockMembers = new Set([
|
||||
"types",
|
||||
"props",
|
||||
"computed",
|
||||
"effect",
|
||||
"watch",
|
||||
"lifecycle",
|
||||
"view",
|
||||
"seo",
|
||||
"security",
|
||||
"load",
|
||||
"action",
|
||||
"api",
|
||||
"ssr",
|
||||
"client",
|
||||
"realtime",
|
||||
"style",
|
||||
"functions",
|
||||
]);
|
||||
|
||||
if (blockMembers.has(identifier.name)) {
|
||||
let cursor = index;
|
||||
let parenthesisDepth = 0;
|
||||
let bracketDepth = 0;
|
||||
let memberQuote = null;
|
||||
let memberEscaped = false;
|
||||
|
||||
while (cursor < bodyEnd) {
|
||||
const current = source[cursor];
|
||||
|
||||
if (memberQuote !== null) {
|
||||
if (memberEscaped) {
|
||||
memberEscaped = false;
|
||||
} else if (current === "\\") {
|
||||
memberEscaped = true;
|
||||
} else if (current === memberQuote) {
|
||||
memberQuote = null;
|
||||
}
|
||||
|
||||
cursor += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === '"' || current === "'") {
|
||||
memberQuote = current;
|
||||
cursor += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === "(") parenthesisDepth += 1;
|
||||
if (current === ")") parenthesisDepth = Math.max(0, parenthesisDepth - 1);
|
||||
if (current === "[") bracketDepth += 1;
|
||||
if (current === "]") bracketDepth = Math.max(0, bracketDepth - 1);
|
||||
|
||||
if (current === "{" && parenthesisDepth === 0 && bracketDepth === 0) {
|
||||
index = cursor;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor += 1;
|
||||
}
|
||||
|
||||
if (cursor >= bodyEnd) index = bodyEnd;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,11 +179,14 @@ function parseOpeningTag(value) {
|
||||
|
||||
const inlineClosing = remainder === `</${tagName}>`;
|
||||
|
||||
const closesInRemainder = remainder.startsWith(`</${tagName}>`);
|
||||
|
||||
return {
|
||||
tagName,
|
||||
attributes,
|
||||
selfClosing,
|
||||
inlineClosing,
|
||||
closesInRemainder,
|
||||
remainder,
|
||||
};
|
||||
}
|
||||
@@ -202,7 +205,11 @@ function formatOpeningTag(value, unit, depth, printWidth = 100) {
|
||||
|
||||
const attributeIndent = unit.repeat(depth + 1);
|
||||
|
||||
const normalizedSingleLine = value.replace(/\s+/g, " ").trim();
|
||||
const normalizedOpening = `<${parsed.tagName}${
|
||||
parsed.attributes.length ? ` ${parsed.attributes.join(" ")}` : ""
|
||||
}${parsed.selfClosing ? " /" : ""}>`;
|
||||
|
||||
const normalizedSingleLine = `${normalizedOpening}${parsed.remainder}`;
|
||||
|
||||
const shouldBreak =
|
||||
parsed.attributes.length > 1 ||
|
||||
@@ -212,6 +219,7 @@ function formatOpeningTag(value, unit, depth, printWidth = 100) {
|
||||
const opensElement =
|
||||
!parsed.selfClosing &&
|
||||
!parsed.inlineClosing &&
|
||||
!parsed.closesInRemainder &&
|
||||
!VOID_ELEMENTS.has(parsed.tagName.toLowerCase());
|
||||
|
||||
if (!shouldBreak) {
|
||||
@@ -375,7 +383,9 @@ function collectOpeningTag(inputLines, startIndex) {
|
||||
}
|
||||
|
||||
return {
|
||||
value: collected.join(" "),
|
||||
// Preserve the fact that the opening tag was already multiline so a
|
||||
// second formatter pass cannot collapse it back to one line.
|
||||
value: collected.join("\n"),
|
||||
endIndex: index,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user