Skip to content

Commit

Permalink
fix(macros/CSSSupport): support nested @webref/css values (#10183)
Browse files Browse the repository at this point in the history
* test(macros/CSSSyntax): add <angle-percentage> test

* refactor(macros/CSSSyntax): rename valuespaces to values

* fix(macros/CSSSyntax): resolve child values

* test(macros/CSSSyntax): update snapshot

* test(macros/CSSSyntax): add polygon() test

* test(macros/CSSSyntax): add <content-replacement> test
  • Loading branch information
caugner authored Dec 14, 2023
1 parent 5c3841a commit b783aa9
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
39 changes: 26 additions & 13 deletions kumascript/src/lib/css-syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,18 @@ export async function getCSSSyntax(
const parsedWebRef = await getParsedWebRef();

// get all the value syntaxes
let valuespaces = {};
let values = {};
for (const spec of Object.values(parsedWebRef)) {
valuespaces = { ...valuespaces, ...spec.valuespaces };
// Add parent values.
values = { ...values, ...spec.values };
// Add child values.
[...Object.values(spec.properties), ...Object.values(spec.values)].forEach(
(value) => {
if ("values" in value && Array.isArray(value.values)) {
values = { ...byName(value.values), ...values };
}
}
);
}

/**
Expand Down Expand Up @@ -216,16 +225,16 @@ export async function getCSSSyntax(
itemName = itemName.replace("_value", "");
}
// not all types have an entry in the syntax
if (valuespaces[itemName]) {
itemSyntax = valuespaces[itemName].value;
if (values[itemName]) {
itemSyntax = values[itemName].value;
}
itemName = `<${itemName}>`;
break;
case "css-function":
itemName = `${itemName}()`;
// not all functions have an entry in the syntax
if (valuespaces[itemName]) {
itemSyntax = valuespaces[itemName].value;
if (values[itemName]) {
itemSyntax = values[itemName].value;
}
itemName = `<${itemName}>`;
break;
Expand Down Expand Up @@ -291,7 +300,7 @@ export async function getCSSSyntax(
// If the type is not included in the syntax, or is in "typesToLink",
// link to its dedicated page (don't expand it)
const key = name.replace(/(^<|>$)/g, "");
if (valuespaces[key]?.value && !typesToLink.includes(name)) {
if (values[key]?.value && !typesToLink.includes(name)) {
return span;
} else {
let slug;
Expand Down Expand Up @@ -469,7 +478,7 @@ export async function getCSSSyntax(
// and then get the types in those syntaxes
constituentSyntaxes = [];
for (const constituent of allConstituents.slice(oldConstituentsLength)) {
const constituentSyntaxEntry = valuespaces[constituent];
const constituentSyntaxEntry = values[constituent];

if (constituentSyntaxEntry?.value) {
constituentSyntaxes.push(constituentSyntaxEntry.value);
Expand Down Expand Up @@ -497,8 +506,8 @@ export async function getCSSSyntax(

// and write each one out
for (const type of types) {
if (valuespaces[type] && valuespaces[type].value) {
output += renderSyntax(`&lt;${type}&gt;`, valuespaces[type].value);
if (values[type] && values[type].value) {
output += renderSyntax(`&lt;${type}&gt;`, values[type].value);
output += "<br/>";
}
}
Expand Down Expand Up @@ -531,7 +540,7 @@ async function getParsedWebRef(): Promise<WebRefObjectData> {
spec,
properties: byName(properties),
atrules: byName(atrules),
valuespaces: byName(values),
values: byName(values),
},
]
)
Expand All @@ -540,10 +549,14 @@ async function getParsedWebRef(): Promise<WebRefObjectData> {

function byName<T extends Named>(items: T[]): Record<string, T> {
return Object.fromEntries(
items.map((item) => [item.name.replace(/(^<|>$)/g, ""), item])
items.map((item) => [normalizeName(item.name), item])
);
}

function normalizeName(name: string): string {
return name.replace(/(^<|>$)/g, "");
}

async function getRawWebRefData(): Promise<WebRefArrayData> {
return (await webRefData.listAll()) as WebRefArrayData;
}
Expand All @@ -555,7 +568,7 @@ interface WebRefObjectDataItem {
spec: WebRefSpecEntry;
properties: Record<string, WebRefPropertyEntry>;
atrules: Record<string, WebRefAtruleEntry>;
valuespaces: Record<string, WebRefValuespaceEntry>;
values: Record<string, WebRefValuespaceEntry>;
}

// @webref/css v6 interfaces.
Expand Down
8 changes: 7 additions & 1 deletion kumascript/tests/lib/__snapshots__/css-syntax.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ exports[`CSSSyntax renders at-rule: @import 1`] = `"<pre><span class="token prop

exports[`CSSSyntax renders at-rule-descriptor: @font-face/src 1`] = `"<pre><span class="token property" id="src">src = </span><br/> <a href="/en-US/docs/Web/CSS/font-src-list"><span class="token property">&lt;font-src-list&gt;</span></a> <br/><br/></pre>"`;

exports[`CSSSyntax renders function: polygon 1`] = `"<pre><span class="token property" id="&lt;polygon()&gt;">&lt;polygon()&gt; = </span><br/> <span class="token function">polygon(</span> <span class="token property"><'fill-rule'></span><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> , <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> <span class="token property">&lt;length-percentage&gt;</span> <span class="token property">&lt;length-percentage&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#hash_mark" title="Hash mark: the entity is repeated one or several times, each occurence separated by a comma">#</a> <span class="token function">)</span> <br/><br/><span class="token property" id="&lt;length-percentage&gt;">&lt;length-percentage&gt; = </span><br/> <a href="/en-US/docs/Web/CSS/length"><span class="token property">&lt;length&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <a href="/en-US/docs/Web/CSS/percentage"><span class="token property">&lt;percentage&gt;</span></a> <br/><br/></pre>"`;

exports[`CSSSyntax renders function: sin 1`] = `"<pre><span class="token property" id="&lt;sin()&gt;">&lt;sin()&gt; = </span><br/> <span class="token function">sin(</span> <span class="token property">&lt;calc-sum&gt;</span> <span class="token function">)</span> <br/><br/><span class="token property" id="&lt;calc-sum&gt;">&lt;calc-sum&gt; = </span><br/> <span class="token property">&lt;calc-product&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> '+' <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a> '-' <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a> <span class="token property">&lt;calc-product&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#asterisk" title="Asterisk: the entity may occur zero, one or several times">*</a> <br/><br/><span class="token property" id="&lt;calc-product&gt;">&lt;calc-product&gt; = </span><br/> <span class="token property">&lt;calc-value&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> '*' <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a> '/' <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a> <span class="token property">&lt;calc-value&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#asterisk" title="Asterisk: the entity may occur zero, one or several times">*</a> <br/><br/><span class="token property" id="&lt;calc-value&gt;">&lt;calc-value&gt; = </span><br/> <a href="/en-US/docs/Web/CSS/number"><span class="token property">&lt;number&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <a href="/en-US/docs/Web/CSS/dimension"><span class="token property">&lt;dimension&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <a href="/en-US/docs/Web/CSS/percentage"><span class="token property">&lt;percentage&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <span class="token property">&lt;calc-keyword&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> ( <span class="token property">&lt;calc-sum&gt;</span> <span class="token function">)</span> <br/><br/><span class="token property" id="&lt;calc-keyword&gt;">&lt;calc-keyword&gt; = </span><br/> <span class="token keyword">e</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <span class="token keyword">pi</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <span class="token keyword">infinity</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <span class="token keyword">-infinity</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <span class="token keyword">NaN</span> <br/><br/></pre>"`;

exports[`CSSSyntax renders property: box-shadow 1`] = `"<pre><span class="token property" id="box-shadow">box-shadow = </span><br/> <span class="token property">&lt;spread-shadow&gt;</span><a href="/en-US/docs/Web/CSS/Value_definition_syntax#hash_mark" title="Hash mark: the entity is repeated one or several times, each occurence separated by a comma">#</a> <br/><br/><span class="token property" id="&lt;spread-shadow&gt;">&lt;spread-shadow&gt; = </span><br/> <span class="token property"><'box-shadow-color'></span><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#double_ampersand" title="Double ampersand: all of the entities must be present, in any order">&&</a><br/> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> <span class="token property"><'box-shadow-offset'></span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> <span class="token property"><'box-shadow-blur'></span> <span class="token property"><'box-shadow-spread'></span><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#double_ampersand" title="Double ampersand: all of the entities must be present, in any order">&&</a><br/> <span class="token property"><'box-shadow-position'></span><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> <br/><br/></pre>"`;

exports[`CSSSyntax renders shorthand-property: overflow 1`] = `"<pre><span class="token property" id="overflow">overflow = </span><br/> <span class="token property"><'overflow-block'></span><a href="/en-US/docs/Web/CSS/Value_definition_syntax#curly_braces" title="Curly braces: encloses two integers defining the minimal and maximal numbers of occurrences of the entity, or a single integer defining the exact number required">{1,2}</a> <br/><br/></pre>"`;

exports[`CSSSyntax renders type: ratio 1`] = `"<pre><span class="token property" id="&lt;ratio&gt;">&lt;ratio&gt; = </span><br/> <a href="/en-US/docs/Web/CSS/number "><span class="token property">&lt;number [0,∞]&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> / <a href="/en-US/docs/Web/CSS/number "><span class="token property">&lt;number [0,∞]&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> <br/><br/></pre>"`;
exports[`CSSSyntax renders type: alpha-value 1`] = `"<pre><span class="token property" id="&lt;alpha-value&gt;">&lt;alpha-value&gt; = </span><br/> <a href="/en-US/docs/Web/CSS/number"><span class="token property">&lt;number&gt;</span></a> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <a href="/en-US/docs/Web/CSS/percentage"><span class="token property">&lt;percentage&gt;</span></a> <br/><br/></pre>"`;

exports[`CSSSyntax renders type: content-replacement 1`] = `"<pre><span class="token property" id="&lt;content-replacement&gt;">&lt;content-replacement&gt; = </span><br/> <span class="token property">&lt;image&gt;</span> <br/><br/><span class="token property" id="&lt;image&gt;">&lt;image&gt; = </span><br/> <span class="token property">&lt;url&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <a href="/en-US/docs/Web/CSS/gradient"><span class="token property">&lt;gradient&gt;</span></a> <br/><br/><span class="token property" id="&lt;url&gt;">&lt;url&gt; = </span><br/> <span class="token property">&lt;url()&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <span class="token property">&lt;src()&gt;</span> <br/><br/><span class="token property" id="&lt;url()&gt;">&lt;url()&gt; = </span><br/> <span class="token function">url(</span> <a href="/en-US/docs/Web/CSS/string"><span class="token property">&lt;string&gt;</span></a> <a href="/en-US/docs/Web/CSS/url-modifier"><span class="token property">&lt;url-modifier&gt;</span></a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#asterisk" title="Asterisk: the entity may occur zero, one or several times">*</a> <span class="token function">)</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#single_bar" title="Single bar: exactly one of the entities must be present">|</a><br/> <a href="/en-US/docs/Web/CSS/url-token"><span class="token property">&lt;url-token&gt;</span></a> <br/><br/><span class="token property" id="&lt;src()&gt;">&lt;src()&gt; = </span><br/> <span class="token function">src(</span> <a href="/en-US/docs/Web/CSS/string"><span class="token property">&lt;string&gt;</span></a> <a href="/en-US/docs/Web/CSS/url-modifier"><span class="token property">&lt;url-modifier&gt;</span></a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#asterisk" title="Asterisk: the entity may occur zero, one or several times">*</a> <span class="token function">)</span> <br/><br/></pre>"`;

exports[`CSSSyntax renders type: ratio 1`] = `"<pre><span class="token property" id="&lt;ratio&gt;">&lt;ratio&gt; = </span><br/> <span class="token property">&lt;number [0,∞]&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">[</a> / <span class="token property">&lt;number [0,∞]&gt;</span> <a href="/en-US/docs/Web/CSS/Value_definition_syntax#brackets" title="Brackets: enclose several entities, combinators, and multipliers to transform them as a single component">]</a><a href="/en-US/docs/Web/CSS/Value_definition_syntax#question_mark" title="Question mark: the entity is optional">?</a> <br/><br/></pre>"`;
10 changes: 10 additions & 0 deletions kumascript/tests/lib/css-syntax.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ describe("CSSSyntax", () => {
});

it("renders function", async () => {
expect(
await render("Web/CSS/basic-shape/polygon", "css-function")
).toMatchSnapshot("polygon");
expect(await render("Web/CSS/sin", "css-function")).toMatchSnapshot("sin");
});

Expand All @@ -42,5 +45,12 @@ describe("CSSSyntax", () => {

it("renders type", async () => {
expect(await render("Web/CSS/ratio", "css-type")).toMatchSnapshot("ratio");
expect(await render("Web/CSS/alpha-value", "css-type")).toMatchSnapshot(
"alpha-value"
);
// Note that Web/CSS/content-replacement doesn't really exist.
expect(
await render("Web/CSS/content-replacement", "css-type")
).toMatchSnapshot("content-replacement");
});
});

0 comments on commit b783aa9

Please sign in to comment.