release: WRNexusJS 0.3.5
This commit is contained in:
@@ -108,3 +108,23 @@ test("extracts explicit prop types and resolves typed prop/state expressions", (
|
||||
);
|
||||
assert.deepEqual(validateComponentTags(input, new Map([["DateInput", target]])), []);
|
||||
});
|
||||
|
||||
test("extracts declared events and validates component event bindings", () => {
|
||||
const target = parseComponentMetadata(`component PinInput {
|
||||
props {
|
||||
value = ""
|
||||
@event complete = function
|
||||
@event clear = function
|
||||
}
|
||||
view { <div></div> }
|
||||
}`);
|
||||
|
||||
assert.deepEqual(target.events, ["complete", "clear"]);
|
||||
assert.deepEqual(
|
||||
validateComponentTags(
|
||||
`<PinInput @complete="save(event)" @missing="fail(event)" />`,
|
||||
new Map([["PinInput", target]]),
|
||||
).map(({ code }) => code),
|
||||
["wrn-unknown-component-event"],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ const {
|
||||
findTopLevelDeclaration,
|
||||
maskLeadingTrivia,
|
||||
validateBalancedCharacters,
|
||||
validateHtmlTags,
|
||||
validateRootMembers,
|
||||
} = require("../src/diagnostics");
|
||||
Module._load = originalLoad;
|
||||
@@ -115,3 +116,37 @@ test("accepts all WRN 0.3 root members without false unknown-member errors", ()
|
||||
|
||||
assert.deepEqual(validateRootMembers(document, source, declaration.kind, declaration.match), []);
|
||||
});
|
||||
|
||||
test("ignores member-like words inside component line and block comments", () => {
|
||||
const source = `component Counter {
|
||||
// Props are passed as attributes on the mount element.
|
||||
/* State and View are explained here, not declared here. */
|
||||
props {
|
||||
start = 0
|
||||
label = "Count"
|
||||
}
|
||||
state count = start
|
||||
view { <button>{label}: {count}</button> }
|
||||
}`;
|
||||
const declaration = findTopLevelDeclaration({}, source);
|
||||
|
||||
assert.deepEqual(
|
||||
validateRootMembers(mockDocument(source), source, declaration.kind, declaration.match),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
test("ignores HTML-like tags inside WRN comments", () => {
|
||||
const source = `// The <section> below listens for child events.
|
||||
// <ComboBox> is only documentation in this comment.
|
||||
page Test {
|
||||
/*
|
||||
Example markup: <article><strong>Preview</strong></article>
|
||||
*/
|
||||
view {
|
||||
<main><section>Real content</section></main>
|
||||
}
|
||||
}`;
|
||||
|
||||
assert.deepEqual(validateHtmlTags(mockDocument(source), source), []);
|
||||
});
|
||||
|
||||
@@ -20,6 +20,15 @@ test("preserves nested prop defaults while formatting", () => {
|
||||
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2 }), formatted);
|
||||
});
|
||||
|
||||
test("formats public event declarations as individual props members", () => {
|
||||
const source = `component Search {\nprops { value = "" @event search = function @event clear = function }\nview { <input/> }\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 {
|
||||
@@ -37,3 +46,139 @@ test("keeps long inline-closing tags idempotent after multiline expansion", () =
|
||||
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 {
|
||||
<button type="button" class="primary" @click='save()'>Save</button>
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const expected = `component Button {
|
||||
view {
|
||||
<button
|
||||
type="button"
|
||||
class="primary"
|
||||
@click='save()'
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
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 {
|
||||
<FeatureList items='{[{ label: "A" }]}' emptyLabel="No items" />
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const formatted = formatWrn(source, {
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
printWidth: 100,
|
||||
multilineAttributes: true,
|
||||
});
|
||||
|
||||
assert.match(formatted, /<FeatureList\n/);
|
||||
|
||||
assert.match(formatted, /items='\{\[\{ label: "A" \}\]\}'/);
|
||||
|
||||
assert.match(formatted, /^\s*\/>$/m);
|
||||
});
|
||||
|
||||
test("indents if and each blocks", () => {
|
||||
const source = `page Demo {
|
||||
view {
|
||||
{#if open}
|
||||
{#each items as item}
|
||||
<span>{item.label}</span>
|
||||
{:empty}
|
||||
<p>Empty</p>
|
||||
{/each}
|
||||
{:else}
|
||||
<p>Closed</p>
|
||||
{/if}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const formatted = formatWrn(source, {
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
multilineAttributes: true,
|
||||
});
|
||||
|
||||
assert.match(formatted, /^ {6}\{#each items as item\}$/m);
|
||||
|
||||
assert.match(formatted, /^ {8}<span>/m);
|
||||
|
||||
assert.equal(
|
||||
formatWrn(formatted, {
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
multilineAttributes: true,
|
||||
}),
|
||||
formatted,
|
||||
);
|
||||
});
|
||||
|
||||
test("expands inline if blocks around HTML", () => {
|
||||
const source = `component Button {
|
||||
view {
|
||||
<button>
|
||||
{#if loading}<span class="wire-spinner wire-spinner--inline" aria-hidden="true"></span>{/if}
|
||||
{#if icon}<span class="{icon}"></span>{:else}<span>Fallback</span>{/if}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const expected = `component Button {
|
||||
view {
|
||||
<button>
|
||||
{#if loading}
|
||||
<span
|
||||
class="wire-spinner wire-spinner--inline"
|
||||
aria-hidden="true"
|
||||
>
|
||||
</span>
|
||||
{/if}
|
||||
{#if icon}
|
||||
<span
|
||||
class="{icon}"
|
||||
>
|
||||
</span>
|
||||
{:else}
|
||||
<span>Fallback</span>
|
||||
{/if}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const options = {
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
printWidth: 100,
|
||||
multilineAttributes: true,
|
||||
};
|
||||
|
||||
assert.equal(formatWrn(source, options), expected);
|
||||
assert.equal(formatWrn(expected, options), expected);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user