@wix/origami-lint 1.34.27 → 1.34.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rules/project/home-page-folder.js +3 -3
- package/dist/rules/site-app/apply-and-presets.js +13 -13
- package/dist/rules/site-app/bindings.js +135 -68
- package/dist/rules/site-app/breakpoints.js +6 -6
- package/dist/rules/site-app/css-file-nesting.js +13 -13
- package/dist/rules/site-app/css-layout-properties.js +14 -15
- package/dist/rules/site-app/css-selectors.js +18 -18
- package/dist/rules/site-app/global-styles.js +19 -19
- package/dist/rules/site-app/no-free-code.js +3 -3
- package/dist/rules/site-app/page-structure.js +11 -11
- package/dist/rules/site-app/slot-attributes.js +4 -4
- package/dist/rules/site-app/slot-placement.js +3 -3
- package/dist/rules/site-app/theme-root.js +7 -8
- package/package.json +2 -2
|
@@ -30,7 +30,7 @@ function rootHasNoSlot({ node, rulesApi, report }) {
|
|
|
30
30
|
const slot = rulesApi.getSlot(node);
|
|
31
31
|
if (slot === null || !isRoot(node, rulesApi))
|
|
32
32
|
return;
|
|
33
|
-
report({ check: 'root_has_slot', loc: getLoc(node, rulesApi), message: `The root ${describe(node, rulesApi)} can't have a slot attribute. Remove slot="${slot}"
|
|
33
|
+
report({ check: 'root_has_slot', loc: getLoc(node, rulesApi), message: `The root ${describe(node, rulesApi)} can't have a slot attribute. Remove slot="${slot}".` });
|
|
34
34
|
}
|
|
35
35
|
/** The root element: the top of Structure, or the element a <Remove> / <Interaction> at the top holds (the page model makes that wrapper the root). */
|
|
36
36
|
function isRoot(node, rulesApi) {
|
|
@@ -48,7 +48,7 @@ function attributeElementHasNoSlot(element, attribute, { rulesApi, report }) {
|
|
|
48
48
|
const name = getAttributeName(attribute);
|
|
49
49
|
if (LAYER_ATTRIBUTES.includes(name) || rulesApi.getSlot(element) === null)
|
|
50
50
|
return;
|
|
51
|
-
report({ check: 'attribute_child_has_slot', loc: getLoc(element, rulesApi), message: `${describe(element, rulesApi)} is placed in the attribute '${name}' and also has slot="${rulesApi.getSlot(element)}". Remove slot=: its place is the attribute
|
|
51
|
+
report({ check: 'attribute_child_has_slot', loc: getLoc(element, rulesApi), message: `${describe(element, rulesApi)} is placed in the attribute '${name}' and also has slot="${rulesApi.getSlot(element)}". Remove slot=: its place is the attribute.` });
|
|
52
52
|
}
|
|
53
53
|
/** Reports an owner that holds elements in its attributes and also has a child with slot=, or an elementProps entry with slots: {…} (CONV-parseJsx.ts:1693). */
|
|
54
54
|
function usesSlotsOnlyOneWay({ node, rulesApi, report }) {
|
|
@@ -56,7 +56,7 @@ function usesSlotsOnlyOneWay({ node, rulesApi, report }) {
|
|
|
56
56
|
return;
|
|
57
57
|
if (!getSlottedChildren(node, rulesApi).length && !hasEntrySlots(node))
|
|
58
58
|
return;
|
|
59
|
-
report({ check: 'mixed_slot_forms', loc: getLoc(node, rulesApi), message: `${describe(node, rulesApi)} places slotted children both in attributes and with slot= (or slots: {…}). Use one way: elements in attributes, or children with slot
|
|
59
|
+
report({ check: 'mixed_slot_forms', loc: getLoc(node, rulesApi), message: `${describe(node, rulesApi)} places slotted children both in attributes and with slot= (or slots: {…}). Use one way: elements in attributes, or children with slot=.` });
|
|
60
60
|
}
|
|
61
61
|
/** Reports a slot key that two children of the owner share (CONV-slots.ts:555), at the later one in the owner's list: children first, then layer elements. */
|
|
62
62
|
function usesEachSlotKeyOnce({ node, rulesApi, report }) {
|
|
@@ -67,7 +67,7 @@ function usesEachSlotKeyOnce({ node, rulesApi, report }) {
|
|
|
67
67
|
if (!other)
|
|
68
68
|
first.set(slot, child);
|
|
69
69
|
else
|
|
70
|
-
report({ check: 'duplicate_slot', loc: getLoc(child, rulesApi), message: `Slot "${slot}" of ${describe(node, rulesApi)} is used by both ${describe(other, rulesApi)} and ${describe(child, rulesApi)}. Give each slotted child its own slot key
|
|
70
|
+
report({ check: 'duplicate_slot', loc: getLoc(child, rulesApi), message: `Slot "${slot}" of ${describe(node, rulesApi)} is used by both ${describe(other, rulesApi)} and ${describe(child, rulesApi)}. Give each slotted child its own slot key.` });
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
// ── reading the owner ──
|
|
@@ -29,8 +29,8 @@ function checkSlotPlaces(slots, { node, rulesApi, report }) {
|
|
|
29
29
|
continue;
|
|
30
30
|
const check = name === ELEMENT_PROPS ? 'element_props_slot_place' : 'attribute_slot_place';
|
|
31
31
|
const message = name === ELEMENT_PROPS
|
|
32
|
-
? `${describe(node, rulesApi)} holds an element in elementProps at a place the import can't write back: put it at a plain data key of the inner part (${place.parts.at(-1) ?? 'partName'}: {content: <…/>})
|
|
33
|
-
: `${describe(node, rulesApi)} holds an element in '${name}' at a place the import can't write back: put it under plain-name keys, give each array item on the way its own string _id, and no . [ ] in keys
|
|
32
|
+
? `${describe(node, rulesApi)} holds an element in elementProps at a place the import can't write back: put it at a plain data key of the inner part (${place.parts.at(-1) ?? 'partName'}: {content: <…/>}).`
|
|
33
|
+
: `${describe(node, rulesApi)} holds an element in '${name}' at a place the import can't write back: put it under plain-name keys, give each array item on the way its own string _id, and no . [ ] in keys.`;
|
|
34
34
|
report({ check, loc: getLoc(element, rulesApi), message });
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -86,7 +86,7 @@ function checkSlotOwnerData(slots, { node, rulesApi, report }) {
|
|
|
86
86
|
const data = rulesApi.getAttributeValue(node, 'data');
|
|
87
87
|
if (!first || data === undefined || isRecord(data))
|
|
88
88
|
return;
|
|
89
|
-
report({ check: 'slot_owner_data_object', loc: getLoc(node, rulesApi), message: `${describe(node, rulesApi)} holds a slot element (in '${first.name}'), so its data must be an object: write data={{…}} or leave data out, not data={${JSON.stringify(data)}}
|
|
89
|
+
report({ check: 'slot_owner_data_object', loc: getLoc(node, rulesApi), message: `${describe(node, rulesApi)} holds a slot element (in '${first.name}'), so its data must be an object: write data={{…}} or leave data out, not data={${JSON.stringify(data)}}.` });
|
|
90
90
|
}
|
|
91
91
|
const isPartName = (name) => PART_NAME.test(name) && !UNSAFE_PART_NAMES.has(name);
|
|
92
92
|
const isPlainKey = (key) => DATA_KEY.test(key) && !RESERVED_KEYS.has(key);
|
|
@@ -34,13 +34,12 @@ export default defineRule({
|
|
|
34
34
|
function isAlone(file, rule, { report }) {
|
|
35
35
|
if (rule.selector === ':root')
|
|
36
36
|
return true;
|
|
37
|
-
reportCssProblem(report, file, rule.line, 'root_selector_suffix', `\`${rule.selector}\` puts a part after :root. Write \`:root { … }\` alone; style elements by their own class (\`.comp-a { … }\`)
|
|
37
|
+
reportCssProblem(report, file, rule.line, 'root_selector_suffix', `\`${rule.selector}\` puts a part after :root. Write \`:root { … }\` alone; style elements by their own class (\`.comp-a { … }\`).`);
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
40
40
|
/** Reports a `:root` rule in a page's own CSS: in style.css (CONV-styleParser.ts:443); in layout.css too, which the import refuses as well (seen live, no tracker row yet). */
|
|
41
41
|
function isNotInPage(file, rule, { report }) {
|
|
42
|
-
|
|
43
|
-
reportCssProblem(report, `${file}.css`, rule.line, 'root_in_page_css', `\`:root\` can't be used in a page's ${file}.css: set site variables in global/themes/theme.css (${source}).`);
|
|
42
|
+
reportCssProblem(report, `${file}.css`, rule.line, 'root_in_page_css', `\`:root\` can't be used in a page's ${file}.css: set site variables in global/themes/theme.css.`);
|
|
44
43
|
}
|
|
45
44
|
/** A theme `:root` rule: a preset (step 4), then only tokens or only the spx context (step 1); an spx context's values (step 2) and place (step 3). A `:root` inside a `@mixin` is the global-styles rows' (its selector must start with `&` there). */
|
|
46
45
|
function checkThemeRoot(root, input) {
|
|
@@ -60,14 +59,14 @@ function hasNoPreset(root, { report }) {
|
|
|
60
59
|
const preset = root.declarations.find(({ prop }) => isPresetProperty(prop));
|
|
61
60
|
if (!preset)
|
|
62
61
|
return true;
|
|
63
|
-
reportCssProblem(report, 'theme.css', root.line, 'preset_on_root', `\`:root\` can't set ${preset.prop}; theme.css holds only :root tokens, the spx context and @mixin global styles. Set a preset on the element's rule in its page's style.css
|
|
62
|
+
reportCssProblem(report, 'theme.css', root.line, 'preset_on_root', `\`:root\` can't set ${preset.prop}; theme.css holds only :root tokens, the spx context and @mixin global styles. Set a preset on the element's rule in its page's style.css.`);
|
|
64
63
|
return false;
|
|
65
64
|
}
|
|
66
65
|
/** Reports a plain property, or tokens mixed with the spx context (CONV-parseTheme.ts:170). 'tokens' / 'spx' when the rule is one of the two. */
|
|
67
66
|
function holdsTokensOrSpx(root, { report }) {
|
|
68
67
|
const plain = root.declarations.find(({ prop }) => !prop.startsWith('--'));
|
|
69
68
|
if (plain) {
|
|
70
|
-
reportCssProblem(report, 'theme.css', root.line, 'non_token_root_property', `this :root rule has \`${plain.prop}\`; a :root rule holds only tokens (--…), or only --spx-ref-width and --spx-resolver-type. Move other properties to an element's rule in style.css
|
|
69
|
+
reportCssProblem(report, 'theme.css', root.line, 'non_token_root_property', `this :root rule has \`${plain.prop}\`; a :root rule holds only tokens (--…), or only --spx-ref-width and --spx-resolver-type. Move other properties to an element's rule in style.css.`);
|
|
71
70
|
return null;
|
|
72
71
|
}
|
|
73
72
|
const spx = root.declarations.filter(isSpx);
|
|
@@ -75,7 +74,7 @@ function holdsTokensOrSpx(root, { report }) {
|
|
|
75
74
|
return 'tokens';
|
|
76
75
|
if (spx.length === root.declarations.length)
|
|
77
76
|
return 'spx';
|
|
78
|
-
reportCssProblem(report, 'theme.css', root.line, 'mixed_spx_context', `this :root rule mixes the spx context (--spx-ref-width, --spx-resolver-type) with other lines; write the spx context as its own :root rule
|
|
77
|
+
reportCssProblem(report, 'theme.css', root.line, 'mixed_spx_context', `this :root rule mixes the spx context (--spx-ref-width, --spx-resolver-type) with other lines; write the spx context as its own :root rule.`);
|
|
79
78
|
return null;
|
|
80
79
|
}
|
|
81
80
|
/** Reports an spx context missing one of its two properties, with a width that isn't a positive plain number, or a resolver that isn't scale / fixed (CONV-parseTheme.ts:177). */
|
|
@@ -84,7 +83,7 @@ function isValidSpxContext(root, { report }) {
|
|
|
84
83
|
const resolver = lastValue(root, '--spx-resolver-type');
|
|
85
84
|
if (width !== undefined && Number.isFinite(Number(width)) && Number(width) > 0 && resolver !== undefined && SPX_RESOLVERS.includes(resolver))
|
|
86
85
|
return true;
|
|
87
|
-
reportCssProblem(report, 'theme.css', root.line, 'invalid_spx_context', `this :root spx rule must set both --spx-ref-width (a positive number, like 1280) and --spx-resolver-type (scale or fixed)
|
|
86
|
+
reportCssProblem(report, 'theme.css', root.line, 'invalid_spx_context', `this :root spx rule must set both --spx-ref-width (a positive number, like 1280) and --spx-resolver-type (scale or fixed).`);
|
|
88
87
|
return false;
|
|
89
88
|
}
|
|
90
89
|
/** Reports an spx context under anything but one `@media (--name)` the theme declares: two conditions, a plain range, another at-rule (CONV-parseTheme.ts:82). At the top level it is the default range's. */
|
|
@@ -94,7 +93,7 @@ function isSpxContextInPlace(root, { rulesApi, report }) {
|
|
|
94
93
|
const name = root.enclosing.length === 1 && root.enclosing[0].startsWith('@media ') ? rulesApi.getBreakpointName(root.enclosing[0].slice('@media '.length)) : null;
|
|
95
94
|
if (name && rulesApi.getCustomMedia('theme').some((breakpoint) => breakpoint.name === name))
|
|
96
95
|
return;
|
|
97
|
-
reportCssProblem(report, 'theme.css', root.line, 'invalid_spx_scope', `set the spx context at the top level or under \`@media (--<named range>)\`, one of the theme's @custom-media names; not under ${root.enclosing.map((atRule) => `\`${atRule}\``).join(', ')}
|
|
96
|
+
reportCssProblem(report, 'theme.css', root.line, 'invalid_spx_scope', `set the spx context at the top level or under \`@media (--<named range>)\`, one of the theme's @custom-media names; not under ${root.enclosing.map((atRule) => `\`${atRule}\``).join(', ')}.`);
|
|
98
97
|
}
|
|
99
98
|
// ── reading the CSS ──
|
|
100
99
|
/** Every rule whose selector starts with `:root` in a parsed file, in order, with what's around it and its declarations. No file → none. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/origami-lint",
|
|
3
|
-
"version": "1.34.
|
|
3
|
+
"version": "1.34.28",
|
|
4
4
|
"description": "Offline lint for an exported Origami site: lints the pages that changed since the last passing run",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
]
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
-
"falconPackageHash": "
|
|
55
|
+
"falconPackageHash": "97fa36a3eb31cb9ae9a81f66fff2679fde030431f3b1767dcaf5154a"
|
|
56
56
|
}
|