"use strict";
const assert = require("node:assert");
const { test } = require("node:test");
const { formatWrn } = require("../src/formatter");
test("formats compact props blocks with one prop per line", () => {
const source = `component Header {\nprops { eyebrow = "" title = "" description = "" align = "start" class = "" }\nview { }\n}\n`;
const expected = `component Header {\n props {\n eyebrow = ""\n title = ""\n description = ""\n align = "start"\n class = ""\n }\n view { }\n}\n`;
assert.equal(formatWrn(source, { insertSpaces: true, tabSize: 2 }), expected);
});
test("preserves nested prop defaults while formatting", () => {
const source = `component Grid {\nprops { items = [{ label: "A" }, { label: "B" }] options = { gap: 4, dense: false } class = "" }\nview {
}\n}\n`;
const formatted = formatWrn(source, { insertSpaces: true, tabSize: 2 });
assert.match(formatted, /items = \[\{ label: "A" \}, \{ label: "B" \}\]/);
assert.match(formatted, /options = \{ gap: 4, dense: false \}/);
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2 }), formatted);
});
test("formats large typed JSON prop defaults with the bundled formatter", () => {
const source = `component Catalog {
props {
categories: unknown[] = [{"label":"Platform & Core","apps":[{"label":"Home","href":"/home"},{"label":"SSO","href":"/sso"}]},{"label":"Sales","apps":[{"label":"CRM","href":"/crm"}]}]
}
view { }
}`;
const formatted = formatWrn(source, { insertSpaces: true, tabSize: 2, printWidth: 70 });
assert.match(formatted, /categories: unknown\[\] = \[\n \{/);
assert.match(formatted, /"apps": \[\n \{/);
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2, printWidth: 70 }), formatted);
});
test("formats native JSON state values with readable indentation", () => {
const source = `component Footer {
state footerItems = [{"label":"Accessibility","href":"/accessibility","value":"accessibility"},{"label":"Privacy","href":"/privacy","value":"privacy"}]
view { }
}
`;
const expected = `component Footer {
state footerItems = [
{
"label": "Accessibility",
"href": "/accessibility",
"value": "accessibility"
},
{
"label": "Privacy",
"href": "/privacy",
"value": "privacy"
}
]
view { }
}
`;
const options = { insertSpaces: true, tabSize: 2 };
assert.equal(formatWrn(source, options), expected);
assert.equal(formatWrn(expected, options), expected);
});
test("formats direct structured component props and preserves expression props", () => {
const source = `component Demo {
view {
}
}
`;
const expected = `component Demo {
view {
}
}
`;
const options = { insertSpaces: true, tabSize: 2, multilineAttributes: true };
assert.equal(formatWrn(source, options), expected);
assert.equal(formatWrn(expected, options), expected);
});
test("formats public event declarations as individual props members", () => {
const source = `component Search {\nprops { value = "" @event search = function @event clear = function }\nview { }\n}\n`;
const formatted = formatWrn(source, { insertSpaces: true, tabSize: 2 });
assert.match(formatted, / {4}@event search = function/);
assert.match(formatted, / {4}@event clear = function/);
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2 }), formatted);
});
test("keeps long inline-closing tags idempotent after multiline expansion", () => {
const source = `component Status {
view {
}
}
`;
const options = { insertSpaces: true, tabSize: 2, printWidth: 100 };
const formatted = formatWrn(source, options);
assert.equal(formatWrn(formatted, options), formatted);
assert.match(formatted, /<\/span>Loading/);
});
test("formats inline elements with one attribute per line", () => {
const source = `component Button {
view {
}
}
`;
const expected = `component Button {
view {
}
}
`;
const options = {
insertSpaces: true,
tabSize: 2,
printWidth: 100,
multilineAttributes: true,
};
assert.equal(formatWrn(source, options), expected);
assert.equal(formatWrn(expected, options), expected);
});
test("formats self-closing component props", () => {
const source = `component Demo {
view {
}
}
`;
const formatted = formatWrn(source, {
insertSpaces: true,
tabSize: 2,
printWidth: 100,
multilineAttributes: true,
});
assert.match(formatted, /$/m);
});
test("indents if and each blocks", () => {
const source = `page Demo {
view {
{#if open}
{#each items as item}
{item.label}
{:empty}
Empty
{/each}
{:else}
Closed
{/if}
}
}
`;
const formatted = formatWrn(source, {
insertSpaces: true,
tabSize: 2,
multilineAttributes: true,
});
assert.match(formatted, /^ {6}\{#each items as item\}$/m);
assert.match(formatted, /^ {8}/m);
assert.equal(
formatWrn(formatted, {
insertSpaces: true,
tabSize: 2,
multilineAttributes: true,
}),
formatted,
);
});
test("expands inline if blocks around HTML", () => {
const source = `component Button {
view {
}
}
`;
const expected = `component Button {
view {
}
}
`;
const options = {
insertSpaces: true,
tabSize: 2,
printWidth: 100,
multilineAttributes: true,
};
assert.equal(formatWrn(source, options), expected);
assert.equal(formatWrn(expected, options), expected);
});
test("formats v0.6 grouped state and outputs blocks", () => {
const source = `component Demo {\nprops { title: string open: boolean = false }\nstate { count: number = 0 loading = false }\noutputs { confirm(payload: ConfirmPayload) cancel() }\nview { }\n}`;
const formatted = formatWrn(source, { tabSize: 2, insertSpaces: true });
assert.match(formatted, /\n {2}state \{\n {4}count: number = 0\n {4}loading = false\n {2}\}/);
assert.match(
formatted,
/\n {2}outputs \{\n {4}confirm\(payload: ConfirmPayload\)\n {4}cancel\(\)\n {2}\}/,
);
});
test("preserves preformatted WRN code examples", () => {
const source = `page Docs {
view {
// One project, one language
page ProductDashboard {
state count: number = 0
<button @click='count++'>Ship {count}</button>
}
}
}
`;
const options = { insertSpaces: true, tabSize: 2, printWidth: 100 };
const formatted = formatWrn(source, options);
assert.match(
formatted,
/\/\/ One project, one language<\/span>\npage<\/span>/,
);
assert.equal(formatWrn(formatted, options), formatted);
});
test("keeps attribute-free opening tags intact when content is long", () => {
const source = `page Docs {
view {
This documentation sentence is deliberately long enough to exceed the formatter print width without splitting the p opening delimiter.
}
}
`;
const options = { insertSpaces: true, tabSize: 2, printWidth: 70 };
const formatted = formatWrn(source, options);
assert.match(formatted, /^ {4}$/m);
assert.doesNotMatch(formatted, /^ {4}
$/m);
assert.equal(formatWrn(formatted, options), formatted);
});
test("preserves balanced compact sibling markup without indentation drift", () => {
const source = `page Compact {
view {
Page→API
}
}\n`;
const formatted = formatWrn(source, { tabSize: 2, printWidth: 80 });
assert.match(formatted, /Page<\/span>→<\/b>API<\/span><\/div>/);
assert.equal(formatWrn(formatted, { tabSize: 2, printWidth: 80 }), formatted);
});