@wix/origami-lint 1.34.42 → 1.34.44

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.
@@ -35,7 +35,7 @@ const ITEM_PROPS = {
35
35
  bottom: SIZE,
36
36
  left: SIZE,
37
37
  right: SIZE,
38
- 'z-index': { reads: (value) => value === 'auto' || /^calc\(\s*infinity\s*\)$/.test(value), allowed: 'calc(infinity), auto' },
38
+ 'z-index': { reads: (value) => value === 'auto' || /^calc\(\s*infinity\s*\)$/.test(value), allowed: 'calc(infinity), auto, or a layer: 1, 51, 100000' },
39
39
  'align-self': SELF_ALIGNMENT,
40
40
  'justify-self': SELF_ALIGNMENT,
41
41
  'scroll-snap-align': keywords('start', 'center', 'end', 'none'),
@@ -83,6 +83,12 @@ const CONTAINER_PROPS = {
83
83
  /** A property allowed at the top of a rule with `@origami-target` blocks (isRootLayoutProperty): the element's own, item and spx properties, and the root-target container property. */
84
84
  const isRootProperty = (prop) => prop in ELEMENT_PROPS || prop in ITEM_PROPS || SPX_PROPS.includes(prop) || CONTAINER_PROPS[prop]?.target === 'root';
85
85
  const isLayoutProperty = (prop) => isRootProperty(prop) || prop in CONTAINER_PROPS;
86
+ /** The element's transformation in layout.css (isLayoutTransformationDeclaration): these properties, and a z-index at a zLayer's value (Z_INDEXES). */
87
+ const TRANSFORMATION_PROPS = ['opacity', 'transform', 'transform-origin', 'filter'];
88
+ const Z_LAYER_INDEXES = ['1', '51', '100000'];
89
+ const isTransformation = (prop, value) => TRANSFORMATION_PROPS.includes(prop) || (prop === 'z-index' && Z_LAYER_INDEXES.includes(value.trim()));
90
+ /** A rule's top-level declarations as the import reads its layout: without the transformation, which it takes out first (withoutTransformationsOf). */
91
+ const withoutTransformation = (declarations) => declarations.filter((decl) => !isTransformation(decl.prop, decl.value));
86
92
  export default defineRule({
87
93
  name: 'css-layout-properties',
88
94
  checks: CHECKS,
@@ -104,7 +110,9 @@ function checkLayoutFile(input) {
104
110
  const blocks = readLayoutRuleBlocks(root);
105
111
  for (const block of blocks)
106
112
  checkBlock(block, reportAt);
107
- const scopes = mergeLayoutScopes(blocks);
113
+ // The import takes the transformation out of each rule before it reads the layout (withoutTransformationsOf), so `z-index: 5; z-index: 51` keeps the 5 as layout
114
+ const scopes = mergeLayoutScopes(blocks.map((block) => ({ ...block, declarations: withoutTransformation(block.declarations) })));
115
+ checkTransformationValues(blocks, reportAt);
108
116
  const defaultTypes = new Map();
109
117
  for (const scope of scopes) {
110
118
  const inherited = scope.media === null ? undefined : defaultTypes.get(scope.element);
@@ -115,7 +123,7 @@ function checkLayoutFile(input) {
115
123
  }
116
124
  /** Each property once per block (:498); a rule without targets holds layout properties (:505); with targets, root properties at the top (:512) and each container property in its target (:524). */
117
125
  function checkBlock(block, reportAt) {
118
- checkPropertiesOnce(block.declarations, `${block.element}'s rule`, reportAt);
126
+ checkPropertiesOnce(withoutTransformation(block.declarations), `${block.element}'s rule`, reportAt);
119
127
  for (const [target, declarations] of block.targets)
120
128
  checkPropertiesOnce(declarations, `${block.element}'s \`@origami-target ${target}\` block`, reportAt);
121
129
  checkOwnRefWidth(block, reportAt);
@@ -134,7 +142,7 @@ function checkPropertiesOnce(declarations, where, reportAt) {
134
142
  }
135
143
  }
136
144
  function checkLayoutPropertiesOnly({ element, declarations }, reportAt) {
137
- for (const decl of declarations) {
145
+ for (const decl of withoutTransformation(declarations)) {
138
146
  if (!isLayoutProperty(decl.prop))
139
147
  reportAt(decl, 'non_layout_property', `${describeNonLayoutProperty(decl.prop, element)}.`);
140
148
  }
@@ -147,7 +155,7 @@ function describeNonLayoutProperty(prop, element) {
147
155
  return `\`${prop}\` on ${element} is not a layout property: move it to ${element}'s rule in style.css`;
148
156
  }
149
157
  function checkRootPropertiesAtTop({ element, declarations }, reportAt) {
150
- for (const decl of declarations) {
158
+ for (const decl of withoutTransformation(declarations)) {
151
159
  if (isRootProperty(decl.prop))
152
160
  continue;
153
161
  const container = CONTAINER_PROPS[decl.prop];
@@ -170,11 +178,22 @@ function checkTargetProperties(element, target, declarations, reportAt) {
170
178
  reportAt(decl, 'property_in_wrong_target', `${element}'s \`${decl.prop}\` goes ${place}, not in ${target}.`);
171
179
  }
172
180
  else {
173
- const fix = isLayoutProperty(decl.prop) ? `move it to the top of ${element}'s rule` : `move it to ${element}'s rule in style.css`;
181
+ // A transformation is taken out at the top of the rule only (withoutTransformationsOf reads a rule's own declarations, not its targets)
182
+ const fix = isLayoutProperty(decl.prop) || TRANSFORMATION_PROPS.includes(decl.prop) ? `move it to the top of ${element}'s rule` : `move it to ${element}'s rule in style.css`;
174
183
  reportAt(decl, 'non_container_target_property', `\`${decl.prop}\` in ${element}'s \`@origami-target ${target}\` block is not a container property: ${fix}.`);
175
184
  }
176
185
  }
177
186
  }
187
+ /** A transformation at a rule's top has a value: the import reads each one by its last declaration per element and breakpoint (cssByNameOf), so an empty one before a value is not read. */
188
+ function checkTransformationValues(blocks, reportAt) {
189
+ const transformations = blocks.map((block) => ({ ...block, declarations: block.declarations.filter((decl) => isTransformation(decl.prop, decl.value)), targets: new Map() }));
190
+ for (const { element, values } of mergeLayoutScopes(transformations)) {
191
+ for (const [prop, decl] of values) {
192
+ if (decl.value.trim() === '')
193
+ reportAt(decl, 'missing_property_value', `${element}'s \`${prop}\` has no value: write a value or remove the declaration.`);
194
+ }
195
+ }
196
+ }
178
197
  /** An element at one breakpoint: its spx reference (:417), its container type (:218), each value (:430, :437, :440, :447), a display for its targets (:451), grid-row with grid-column (:264). Returns the container type, for the breakpoints that inherit it. */
179
198
  function checkScope(scope, inherited, reportAt) {
180
199
  const { element, values } = scope;
@@ -187,8 +206,8 @@ function checkScope(scope, inherited, reportAt) {
187
206
  reportAt(decl, 'missing_property_value', `${element}'s \`${prop}\` has no value: write a value or remove the declaration.`);
188
207
  continue;
189
208
  }
190
- if (SPX_PROPS.includes(prop))
191
- continue;
209
+ if (SPX_PROPS.includes(prop) || isTransformation(prop, value))
210
+ continue; // a transformation in a target block: checkTargetProperties reports it
192
211
  const container = CONTAINER_PROPS[prop];
193
212
  if (container && type && !container[type]) {
194
213
  const [own, other] = type === 'grid' ? ['grid', 'flex'] : ['flex', 'grid'];
@@ -305,7 +324,8 @@ const getItems = ({ node, rulesApi }) => rulesApi.getItemElements(node).flatMap(
305
324
  function checkContainerParent(child, parent, { report, rulesApi }) {
306
325
  const byMedia = new Map();
307
326
  for (const prop of Object.keys(ITEM_PROPS)) {
308
- for (const decl of (child.css.layout[prop] ?? []).filter(isOnElement))
327
+ const layout = (child.css.layout[prop] ?? []).filter((decl) => isOnElement(decl) && !isTransformation(prop, decl.value)); // a zLayer z-index is no item property
328
+ for (const decl of layout)
309
329
  byMedia.set(decl.media, [...(byMedia.get(decl.media) ?? []), { prop, decl }]);
310
330
  }
311
331
  for (const [media, declarations] of byMedia) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/origami-lint",
3
- "version": "1.34.42",
3
+ "version": "1.34.44",
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": {
@@ -26,7 +26,7 @@
26
26
  "eslint": "^10.12.0",
27
27
  "postcss": "^8.5.3",
28
28
  "typescript": "^5.8.3 || ~6.0.3",
29
- "@wix/origami-bi": "0.17.0"
29
+ "@wix/origami-bi": "0.18.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",
@@ -54,5 +54,5 @@
54
54
  ]
55
55
  }
56
56
  },
57
- "falconPackageHash": "75ff158491c0d257f4c8c0c0a34a9cff8171ca1a8112cfe25b219155"
57
+ "falconPackageHash": "dd56bf015e4bd3779535e6af5723b0f06fe7f30031097ebd9e6a964e"
58
58
  }