fix(editor): type nested attribute expressions
Quality / quality (ubuntu-latest) (push) Failing after 9m52s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-25 15:16:38 +05:30
parent 3cb6ba1233
commit 7658c5d499
12 changed files with 193 additions and 22 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/typecheck",
"version": "0.8.15",
"version": "0.8.16",
"type": "module",
"main": "src/index.ts",
"exports": {
+5 -1
View File
@@ -3,6 +3,7 @@ import { dirname, join, normalize, resolve } from "node:path";
import ts from "typescript";
import {
containsReadonlyPropMutation,
extractInterpolations,
inferredRuntimeType,
parse,
runtimeTypeOf,
@@ -332,6 +333,9 @@ export function virtualTypeScriptModule(
if (ast.dataApis.length) append(`declare const api: { ${apiType} };`);
append(`declare const props: Readonly<${ast.name}Props>;`);
append("declare const refs: Record<string, Element | null>;");
append(
"declare const toast: ((message: string, options?: Record<string, unknown>) => unknown) & { success(message: string, options?: Record<string, unknown>): unknown; error(message: string, options?: Record<string, unknown>): unknown; danger(message: string, options?: Record<string, unknown>): unknown; warning(message: string, options?: Record<string, unknown>): unknown; info(message: string, options?: Record<string, unknown>): unknown; dismiss(id: string | number): void; clear(): void };",
);
append(
"declare function useFetch(path: string, method?: string | { method?: string; query?: unknown; params?: unknown; body?: unknown; data?: unknown }, input?: unknown): Promise<any>;",
);
@@ -382,7 +386,7 @@ export function virtualTypeScriptModule(
for (const attr of node.attrs) {
const expressions = attr.event
? [attr.value]
: [...attr.value.matchAll(/\{([^{}]+)\}/g)].map((match) => match[1]!.trim());
: extractInterpolations(attr.value).map((segment) => segment.expression);
for (const expression of expressions) {
if (!expression.trim()) continue;
const declarations = [
+29
View File
@@ -112,3 +112,32 @@ test("accepts handler payload, loop locals, and the public useFetch helper", ()
);
expect(diagnostics.filter((diagnostic) => diagnostic.code === "WRN-TYPE-2304")).toEqual([]);
});
test("accepts multiline array props containing nested object literals", () => {
const root = app();
const diagnostics = checkWrnSource(
`page Contact {
view {
<div data-component="StatsBar" items="{[
{ label: 'Product catalog', value: '81', suffix: ' apps' },
{ label: 'Starting point', value: 'One workflow' }
]}"></div>
}
}`,
{ appRoot: root, filePath: join(root, "app", "pages", "contact.wrn") },
);
expect(diagnostics.filter((diagnostic) => diagnostic.code.startsWith("WRN-TYPE-"))).toEqual([]);
});
test("provides the toast API to view event expressions", () => {
const root = app();
const diagnostics = checkWrnSource(
`page Contact {
view {
<form @wrn:success="toast.success('Sent', { title: 'Request sent' })"></form>
}
}`,
{ appRoot: root, filePath: join(root, "app", "pages", "contact.wrn") },
);
expect(diagnostics.filter((diagnostic) => diagnostic.code.startsWith("WRN-TYPE-"))).toEqual([]);
});