release: WRNexusJS 0.2.32
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -357,6 +357,15 @@ const MIGRATIONS: Migration[] = [
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.2.32",
|
||||
id: "fix-runtime-bug",
|
||||
description:
|
||||
"Fixes safe encoding and browser parsing of multiline component behavior metadata.",
|
||||
apply() {
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -925,7 +925,9 @@ function behaviorAttribute(behavior: ComponentBehavior | null): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ` data-wrn-behavior="${attrEscape(JSON.stringify(behavior))}"`;
|
||||
const encoded = encodeURIComponent(JSON.stringify(behavior));
|
||||
|
||||
return ` data-wrn-behavior="${encoded}"`;
|
||||
}
|
||||
|
||||
const INTERP_RE = /\{([^{}]+)\}/g;
|
||||
|
||||
@@ -382,11 +382,11 @@ component LifecycleTest {
|
||||
`),
|
||||
);
|
||||
|
||||
expect(output).toContain(""mount"");
|
||||
expect(output).toContain("%22mount%22");
|
||||
|
||||
expect(output).toContain(""update"");
|
||||
expect(output).toContain("%22update%22");
|
||||
|
||||
expect(output).toContain(""unmount"");
|
||||
expect(output).toContain("%22unmount%22");
|
||||
});
|
||||
test("component watchers compile into behavior metadata", () => {
|
||||
const output = generate(
|
||||
@@ -405,7 +405,7 @@ component WatchTest {
|
||||
`),
|
||||
);
|
||||
|
||||
expect(output).toContain(""state":"visible"");
|
||||
expect(output).toContain("%22state%22%3A%22visible%22");
|
||||
|
||||
expect(output).toContain("console.log");
|
||||
});
|
||||
@@ -436,3 +436,121 @@ component BehaviorOnly {
|
||||
|
||||
expect(output).toContain("data-wrn-behavior");
|
||||
});
|
||||
test("component behavior metadata safely encodes multiline code", () => {
|
||||
const output = generate(
|
||||
parse(`
|
||||
component BackToTop {
|
||||
state visible = false
|
||||
|
||||
functions {
|
||||
function updateVisibility() {
|
||||
visible = window.scrollY > 500
|
||||
}
|
||||
|
||||
function scrollToTop() {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: "smooth"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
mount {
|
||||
updateVisibility()
|
||||
}
|
||||
}
|
||||
|
||||
watch visible {
|
||||
console.log(
|
||||
value,
|
||||
previous
|
||||
)
|
||||
}
|
||||
|
||||
view {
|
||||
<button @click="scrollToTop()">
|
||||
Top
|
||||
</button>
|
||||
}
|
||||
}
|
||||
`),
|
||||
);
|
||||
|
||||
expect(output).toContain("data-wrn-behavior=");
|
||||
|
||||
expect(output).toContain("%7B");
|
||||
expect(output).toContain("%22functions%22");
|
||||
|
||||
expect(output).not.toContain('data-wrn-behavior="{');
|
||||
});
|
||||
|
||||
test("component watchers compile into behavior metadata", () => {
|
||||
const output = generate(
|
||||
parse(`
|
||||
component WatchTest {
|
||||
state visible = false
|
||||
|
||||
watch visible {
|
||||
console.log("changed", visible)
|
||||
}
|
||||
|
||||
view {
|
||||
<div>{visible}</div>
|
||||
}
|
||||
}
|
||||
`),
|
||||
);
|
||||
|
||||
const match = /data-wrn-behavior="([^"]+)"/.exec(output);
|
||||
|
||||
expect(match).not.toBeNull();
|
||||
|
||||
const behavior = JSON.parse(decodeURIComponent(match![1]));
|
||||
|
||||
expect(behavior.watches).toEqual([
|
||||
{
|
||||
state: "visible",
|
||||
body: expect.stringContaining('console.log("changed", visible)'),
|
||||
},
|
||||
]);
|
||||
});
|
||||
test("component lifecycle hooks compile into behavior metadata", () => {
|
||||
const output = generate(
|
||||
parse(`
|
||||
component LifecycleTest {
|
||||
state ready = false
|
||||
|
||||
lifecycle {
|
||||
mount {
|
||||
ready = true
|
||||
}
|
||||
|
||||
update {
|
||||
console.log(ready)
|
||||
}
|
||||
|
||||
unmount {
|
||||
ready = false
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
<div>{ready}</div>
|
||||
}
|
||||
}
|
||||
`),
|
||||
);
|
||||
|
||||
const match = /data-wrn-behavior="([^"]+)"/.exec(output);
|
||||
|
||||
expect(match).not.toBeNull();
|
||||
|
||||
const behavior = JSON.parse(decodeURIComponent(match![1]));
|
||||
|
||||
expect(behavior.lifecycle.mount).toContain("ready = true");
|
||||
|
||||
expect(behavior.lifecycle.update).toContain("console.log(ready)");
|
||||
|
||||
expect(behavior.lifecycle.unmount).toContain("ready = false");
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -44,13 +44,32 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
|
||||
function parseBehavior(element) {
|
||||
var raw = element.getAttribute("data-wrn-behavior");
|
||||
if (!raw) return null;
|
||||
var raw = element.getAttribute(
|
||||
"data-wrn-behavior",
|
||||
);
|
||||
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
var parsed = JSON.parse(raw);
|
||||
return parsed && typeof parsed === "object" ? parsed : null;
|
||||
var decoded = decodeURIComponent(raw);
|
||||
var parsed = JSON.parse(decoded);
|
||||
|
||||
if (
|
||||
!parsed ||
|
||||
typeof parsed !== "object"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
} catch (error) {
|
||||
console.error("[wrnexus] failed to parse component behavior", error);
|
||||
console.error(
|
||||
"[wrnexus] failed to parse component behavior",
|
||||
error,
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.2.31",
|
||||
"version": "0.2.32",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
Reference in New Issue
Block a user