release: WRNexusJS 0.7.0

This commit is contained in:
2026-08-01 10:04:42 +05:30
parent c54144f2e4
commit 87507edf59
207 changed files with 12607 additions and 679 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "wrnexus",
"version": "0.5.0",
"version": "0.7.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wrnexus",
"version": "0.5.0",
"version": "0.7.0",
"license": "SEE LICENSE IN LICENSE",
"devDependencies": {
"@vscode/vsce": "^3.9.2"
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "wrnexus",
"displayName": "WRNexus Language Support",
"description": "Complete WRNexus v0.6 language support for typed imports, props, state, outputs, runtime functions, stores, diagnostics, formatting, navigation, and migration assistance.",
"version": "0.6.0",
"version": "0.7.0",
"publisher": "wrnexus",
"private": true,
"license": "SEE LICENSE IN LICENSE",
+191 -17
View File
@@ -3,6 +3,79 @@
const __nodeRequire = require;
const __path = __nodeRequire("node:path");
const __modules = {
"packages/compiler/src/analysis.ts": function (module, exports, require, __filename, __dirname) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeRuntimeRequirements = analyzeRuntimeRequirements;
function hasEvent(nodes) {
for (const node of nodes) {
if (node.type === "element") {
if (node.attrs.some((attribute) => attribute.event))
return true;
if (hasEvent(node.children))
return true;
}
else if (node.type === "each") {
if (hasEvent(node.body) || hasEvent(node.empty))
return true;
}
else if (node.type === "if") {
if (node.branches.some((branch) => hasEvent(branch.body)))
return true;
}
}
return false;
}
function analyzeRuntimeRequirements(ast) {
const reasons = [];
const clientFunctions = ast.runtimeFunctions.some((fn) => fn.runtime !== "server");
const clientState = ast.states.some((state) => state.runtime !== "server");
const interactive = clientFunctions ||
clientState ||
ast.effects.length > 0 ||
ast.watches.length > 0 ||
hasEvent(ast.view);
if (interactive)
reasons.push("client interactivity");
const requestData = ast.loads.length > 0 ||
ast.actions.length > 0 ||
ast.dataApis.length > 0 ||
ast.apis.length > 0 ||
ast.realtimes.length > 0 ||
ast.runtimeFunctions.some((fn) => fn.runtime === "server") ||
ast.states.some((state) => state.runtime === "server");
if (requestData)
reasons.push("server/request data");
const authenticated = /^(?:required|true)$/i.test(ast.security.auth ?? "");
if (authenticated)
reasons.push("authentication required");
const streaming = /^(?:true|required)$/i.test(ast.security.streaming ?? "");
if (streaming)
reasons.push("streaming enabled");
let kind;
if (streaming)
kind = "streaming-ssr";
else if (authenticated)
kind = "authenticated-ssr";
else if (requestData && interactive)
kind = "dynamic";
else if (requestData)
kind = "request-ssr";
else if (interactive)
kind = "static-interactive";
else
kind = "static";
return {
kind,
canPrerender: kind === "static" || kind === "static-interactive",
needsClientRuntime: interactive && ast.hydrate !== "none" && ast.runtime !== "server",
needsServerRuntime: requestData || authenticated || streaming || ast.runtime === "server",
hydrationStrategy: interactive ? (ast.hydrate ?? "load") : null,
reasons,
};
}
},
"packages/compiler/src/cache.ts": function (module, exports, require, __filename, __dirname) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
@@ -339,6 +412,30 @@ const HTML_BOOLEAN_ATTRIBUTES = new Set([
function isHtmlBooleanAttribute(name) {
return HTML_BOOLEAN_ATTRIBUTES.has(name.toLowerCase());
}
const URL_ATTRIBUTES = new Set([
"href",
"src",
"action",
"formaction",
"poster",
"cite",
"background",
"xlink:href",
]);
function sanitizeUrlAttribute(value) {
const compact = value.trim().replace(/[\u0000-\u0020]+/g, "");
const lower = compact.toLowerCase();
if (/^(?:javascript|vbscript|file):/.test(lower))
return "about:blank";
if (/^data:(?!image\/(?:png|gif|jpeg|webp|avif);)/.test(lower))
return "about:blank";
return value;
}
function safeAttributeValue(name, value) {
if (!URL_ATTRIBUTES.has(name.toLowerCase()) || value.includes("{"))
return value;
return sanitizeUrlAttribute(value);
}
/** Escape a value placed inside a double-quoted HTML attribute. */
function attrEscape(value) {
return value
@@ -368,7 +465,9 @@ function renderAttr(attr) {
case "csrText":
return "";
default:
return attr.boolean ? ` ${attr.name}` : ` ${attr.name}="${attrEscape(attr.value)}"`;
return attr.boolean
? ` ${attr.name}`
: ` ${attr.name}="${attrEscape(safeAttributeValue(attr.name, attr.value))}"`;
}
}
function eventAttribute(name) {
@@ -423,7 +522,7 @@ function renderAttrs(attrs, csrId, reactive = null, dynamicExpressions) {
if (initial === null)
return base;
const marker = JSON.stringify([attr.name, attr.value]);
return ` ${attr.name}="${attrEscape(initial)}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`;
return ` ${attr.name}="${attrEscape(URL_ATTRIBUTES.has(attr.name.toLowerCase()) ? sanitizeUrlAttribute(initial) : initial)}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`;
})
.join("");
return csrId ? `${rendered} data-wrnexus-csr="${attrEscape(csrId)}"` : rendered;
@@ -2009,7 +2108,7 @@ function renderPageComponentAttr(attr, dynamicExpressions) {
}
const expression = wholeAttributeExpression(attr.value);
if (!expression) {
return ` ${attr.name}="${attrEscape(attr.value)}"`;
return ` ${attr.name}="${attrEscape(safeAttributeValue(attr.name, attr.value))}"`;
}
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
const marker = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
@@ -2097,7 +2196,7 @@ function resolveWrnImports(declarations, importer, options) {
* `@wrnexus/syntax` package. This package owns platform-specific codegen.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DependencyGraph = exports.createCompilationCache = exports.compilationKey = exports.runtimeTypeOf = exports.inferredRuntimeType = exports.eraseFunctionTypes = exports.LexError = exports.Lexer = exports.NativeCompileError = exports.generateNative = exports.createWrnSourceMap = exports.resolveWrnImports = exports.resolveWrnImport = exports.createComponentContract = exports.generateStoreModule = exports.generateStoreBrowserModule = exports.generateDeclarations = exports.rpcManifest = exports.generateServerFunctionsModule = exports.generateBrowserModule = exports.generateTargets = exports.generate = exports.ParseError = exports.parse = exports.formatDiagnostic = exports.diagnosticFromError = exports.diagnose = exports.assertValidAst = void 0;
exports.DependencyGraph = exports.createCompilationCache = exports.compilationKey = exports.runtimeTypeOf = exports.inferredRuntimeType = exports.eraseFunctionTypes = exports.LexError = exports.Lexer = exports.NativeCompileError = exports.generateNative = exports.analyzeRuntimeRequirements = exports.createWrnSourceMap = exports.resolveWrnImports = exports.resolveWrnImport = exports.createComponentContract = exports.generateStoreModule = exports.generateStoreBrowserModule = exports.generateDeclarations = exports.rpcManifest = exports.generateServerFunctionsModule = exports.generateBrowserModule = exports.generateTargets = exports.generate = exports.ParseError = exports.parse = exports.formatDiagnostic = exports.diagnosticFromError = exports.diagnose = exports.assertValidAst = void 0;
exports.compileNativeWireFile = compileNativeWireFile;
exports.compileWireFile = compileWireFile;
exports.compile = compile;
@@ -2132,6 +2231,8 @@ Object.defineProperty(exports, "resolveWrnImport", { enumerable: true, get: func
Object.defineProperty(exports, "resolveWrnImports", { enumerable: true, get: function () { return import_resolver_ts_1.resolveWrnImports; } });
var source_map_ts_1 = require("./source-map.js");
Object.defineProperty(exports, "createWrnSourceMap", { enumerable: true, get: function () { return source_map_ts_1.createWrnSourceMap; } });
var analysis_ts_1 = require("./analysis.js");
Object.defineProperty(exports, "analyzeRuntimeRequirements", { enumerable: true, get: function () { return analysis_ts_1.analyzeRuntimeRequirements; } });
var native_codegen_ts_2 = require("./native-codegen.js");
Object.defineProperty(exports, "generateNative", { enumerable: true, get: function () { return native_codegen_ts_2.generateNative; } });
Object.defineProperty(exports, "NativeCompileError", { enumerable: true, get: function () { return native_codegen_ts_2.NativeCompileError; } });
@@ -2649,7 +2750,7 @@ function __diagnostic(code, message, details) {
}
function __csrfToken() {
if (typeof document === "undefined") return undefined;
const match = /(?:^|;\\s*)wrnexus_csrf=([^;]+)/.exec(document.cookie || "");
const match = /(?:^|;\\s*)wire-csrf=([^;]+)/.exec(document.cookie || "");
return match ? decodeURIComponent(match[1]) : undefined;
}
async function __callServerFunction(storeName, functionName, args, options) {
@@ -2660,7 +2761,7 @@ async function __callServerFunction(storeName, functionName, args, options) {
method: "POST",
credentials: "same-origin",
signal: options.signal,
headers: Object.assign({ "content-type": "application/json", "x-request-id": traceId }, csrf ? { "x-wrnexus-csrf": csrf } : {}, options.headers || {}),
headers: Object.assign({ "content-type": "application/json", "x-request-id": traceId }, csrf ? { "x-csrf-token": csrf } : {}, options.headers || {}),
body: JSON.stringify({ component: storeName, function: functionName, args: args }),
});
const payload = await response.json().catch(function () { return null; });
@@ -3129,20 +3230,65 @@ function astDiagnostics(ast, options) {
});
}
let interactive = ast.states.length > 0 || ast.effects.length > 0 || ast.watches.length > 0;
const urlAttributes = new Set(["href", "src", "action", "formaction", "poster", "cite", "background", "xlink:href"]);
walk(ast.view, (node) => {
if (node.type === "element" && node.attrs.some((attribute) => attribute.event))
interactive = true;
if (!options.accessibility || node.type !== "element")
if (node.type !== "element")
return;
if (node.attrs.some((attribute) => attribute.event))
interactive = true;
const tag = node.tag.toLowerCase();
if (tag === "img" && !node.attrs.some((attribute) => attribute.name === "alt")) {
diagnostics.push({
code: spec_ts_1.WRN_DIAGNOSTIC_CODES.accessibility,
severity: "warning",
message: "Image is missing an alt attribute.",
hint: 'Add alt text, or alt="" for a decorative image.',
file: options.file,
});
for (const attribute of node.attrs) {
if (attribute.event || attribute.boolean || !urlAttributes.has(attribute.name.toLowerCase()))
continue;
if (attribute.value.includes("{"))
continue;
const value = attribute.value.trim().replace(/[\u0000-\u0020]+/g, "").toLowerCase();
if (/^(?:javascript|vbscript|file):/.test(value) || /^data:(?!image\/(?:png|gif|jpeg|webp|avif);)/.test(value)) {
diagnostics.push({
code: "WRN-SEC-UNSAFE-URL",
severity: "error",
message: `Unsafe URL protocol in ${attribute.name} on <${node.tag}>.`,
hint: "Use a relative URL, https:, mailto:, tel:, or a framework-validated URL helper.",
file: options.file,
});
}
}
if (tag === "a") {
const target = node.attrs.find((attribute) => attribute.name === "target")?.value;
const rel = node.attrs.find((attribute) => attribute.name === "rel")?.value ?? "";
if (target === "_blank" && !/\bnoopener\b/i.test(rel)) {
diagnostics.push({
code: "WRN-SEC-BLANK-REL",
severity: "warning",
message: "A target=_blank link should include rel=noopener.",
hint: 'Add rel="noopener noreferrer".',
file: options.file,
});
}
}
if (!options.accessibility)
return;
if (tag === "img") {
if (!node.attrs.some((attribute) => attribute.name === "alt")) {
diagnostics.push({
code: spec_ts_1.WRN_DIAGNOSTIC_CODES.accessibility,
severity: "warning",
message: "Image is missing an alt attribute.",
hint: 'Add alt text, or alt="" for a decorative image.',
file: options.file,
});
}
const hasWidth = node.attrs.some((attribute) => attribute.name === "width");
const hasHeight = node.attrs.some((attribute) => attribute.name === "height");
if (!hasWidth || !hasHeight) {
diagnostics.push({
code: "WRN-PERF-IMAGE-DIMENSIONS",
severity: "warning",
message: "Image width and height are required to prevent layout shifts.",
hint: "Declare intrinsic width and height, or use @wrnexus/image.",
file: options.file,
});
}
}
});
if (ast.runtime === "server" && interactive) {
@@ -3171,6 +3317,24 @@ function astDiagnostics(ast, options) {
if (fn.runtime === "server" && /\b(?:window|document|localStorage|sessionStorage|navigator)\b/.test(fn.body)) {
diagnostics.push({ code: "WRN-SERVER-BROWSER-API", severity: "error", message: `Server function '${fn.name}' references a browser-only API.`, hint: "Move that code into a client function.", file: options.file });
}
if (fn.runtime !== "server" && /\b(?:eval\s*\(|new\s+Function\s*\(|document\.write\s*\(|\.innerHTML\s*=|\.outerHTML\s*=|insertAdjacentHTML\s*\()/.test(fn.body)) {
diagnostics.push({
code: "WRN-SEC-DOM-SINK",
severity: "error",
message: `Client function '${fn.name}' uses an unsafe dynamic-code or HTML sink.`,
hint: "Use compiled templates, textContent, typed outputs, or a reviewed TrustedHTML sanitizer.",
file: options.file,
});
}
if (fn.runtime !== "server" && /\b(?:setTimeout|setInterval)\s*\(\s*["'`]/.test(fn.body)) {
diagnostics.push({
code: "WRN-SEC-STRING-TIMER",
severity: "error",
message: `Client function '${fn.name}' passes a string to a timer.`,
hint: "Pass a function instead of executable text.",
file: options.file,
});
}
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
for (const prop of ast.props) {
if (containsReadonlyPropMutation(fn.body, prop.name, parameterNames)) {
@@ -3182,6 +3346,16 @@ function astDiagnostics(ast, options) {
if (state.runtime === "shared" && /^(?:new\s+(?:Map|Set|WeakMap|WeakSet)|(?:async\s+)?function\b|.*=>)/.test(state.expr.trim())) {
diagnostics.push({ code: "WRN-STATE-NON-SERIALIZABLE", severity: "error", message: `Shared state '${state.name}' is not safely serializable.`, hint: "Use JSON-compatible data or move the value into client/server state.", file: options.file });
}
if (state.runtime !== "server" &&
/\b(?:process\.env|Bun\.env|Deno\.env|ctx\.env|import\.meta\.env)\b/.test(state.expr)) {
diagnostics.push({
code: "WRN-SEC-SERVER-SECRET-SOURCE",
severity: "error",
message: `Browser-visible state '${state.name}' reads from a server environment source.`,
hint: "Move environment-backed values into server state and return only an explicitly safe result.",
file: options.file,
});
}
}
if (ast.persist) {
const stateNames = new Set(ast.states.filter((state) => state.runtime !== "server").map((state) => state.name));