@wix/origami-transforms 0.1.7 → 0.1.8
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/origami-transforms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Babel and PostCSS checks and transforms for Wix origami page files.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
},
|
|
55
55
|
"type": "module",
|
|
56
56
|
"types": "./dist/index.d.ts",
|
|
57
|
-
"falconPackageHash": "
|
|
57
|
+
"falconPackageHash": "09b1c7aec92977ffa2db7c85a87daf406d7628c92600cbe85ed3ef94"
|
|
58
58
|
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
// Checks the CSS of a stack's direct children (rule S2-STACK-001). It changes nothing: every violation in the
|
|
2
2
|
// stylesheet is collected, and the build fails once with all of them.
|
|
3
3
|
//
|
|
4
|
-
// A stack is a parent
|
|
5
|
-
// `flex-direction` says which way
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// A stack is a parent laid out with a non-wrapping flex, as DM derives it; an internal container writes its
|
|
5
|
+
// layout in its `@origami-target internal-container-content-wrapper` block. `flex-direction` says which way
|
|
6
|
+
// it stacks (column → vertical, anything else → horizontal, as in CSS).
|
|
7
|
+
//
|
|
8
|
+
// Parent and child are the JSX tree's, so the tree comes from the item's structure file (see
|
|
9
|
+
// structureFile.js). The stylesheet is the page's, with its carriers already inlined (see
|
|
10
|
+
// ../transform/css/postcssPlugin.js), so every rule is in view.
|
|
9
11
|
|
|
10
12
|
import { basename } from 'node:path'
|
|
11
13
|
import { LayoutError } from '../transform/layoutError.js'
|
|
12
14
|
import { literalIdOf, parseStructure, structureFileOf, walk } from './structureFile.js'
|
|
13
15
|
|
|
14
|
-
const
|
|
16
|
+
const CONTENT_WRAPPER = 'internal-container-content-wrapper'
|
|
15
17
|
const BASE = ''
|
|
16
18
|
|
|
17
19
|
// What a stack child may write, per direction. `0` is allowed wherever a length is.
|
|
@@ -79,38 +81,63 @@ const conditionOf = rule => {
|
|
|
79
81
|
return conditions.join(' / ')
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
+
// Exports give an element both `#id` and `.id`, and write its CSS on the class.
|
|
85
|
+
const OWN_SELECTOR = /^([#.])([\w-]+)$/
|
|
86
|
+
|
|
87
|
+
const isContentWrapper = node =>
|
|
88
|
+
node.type === 'atrule' && node.name === 'origami-target' && node.params.trim() === CONTENT_WRAPPER
|
|
89
|
+
|
|
90
|
+
/** Id → condition → `.`/`#` → declarations, in source order. With `content`, a content wrapper block counts. */
|
|
91
|
+
const declarationsById = (root, { content = false } = {}) => {
|
|
84
92
|
const byId = new Map()
|
|
85
93
|
root.walkRules(rule => {
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
94
|
+
const own = rule.selectors.map(selector => OWN_SELECTOR.exec(selector.trim())).filter(Boolean)
|
|
95
|
+
if (!own.length) return
|
|
88
96
|
const condition = conditionOf(rule)
|
|
89
|
-
for (const id of
|
|
97
|
+
for (const [, kind, id] of own) {
|
|
90
98
|
const byCondition = byId.get(id) ?? new Map()
|
|
91
99
|
byId.set(id, byCondition)
|
|
92
|
-
const
|
|
93
|
-
byCondition.set(condition,
|
|
100
|
+
const byKind = byCondition.get(condition) ?? { '.': [], '#': [] }
|
|
101
|
+
byCondition.set(condition, byKind)
|
|
94
102
|
rule.each(node => {
|
|
95
|
-
if (node.type === 'decl')
|
|
103
|
+
if (node.type === 'decl') byKind[kind].push(node)
|
|
104
|
+
else if (content && isContentWrapper(node)) {
|
|
105
|
+
node.each(inner => {
|
|
106
|
+
if (inner.type === 'decl') byKind[kind].push(inner)
|
|
107
|
+
})
|
|
108
|
+
}
|
|
96
109
|
})
|
|
97
110
|
}
|
|
98
111
|
})
|
|
99
112
|
return byId
|
|
100
113
|
}
|
|
101
114
|
|
|
102
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* The declarations in effect under `condition`: the base ones, then the condition's own; `#id` beats `.id`, and
|
|
117
|
+
* `!important` beats both.
|
|
118
|
+
*/
|
|
103
119
|
const effective = (byCondition, condition) => {
|
|
104
120
|
const result = new Map()
|
|
105
|
-
for (const
|
|
106
|
-
for (const
|
|
121
|
+
for (const important of [false, true]) {
|
|
122
|
+
for (const kind of ['.', '#']) {
|
|
123
|
+
for (const key of condition === BASE ? [BASE] : [BASE, condition]) {
|
|
124
|
+
for (const declaration of byCondition?.get(key)?.[kind] ?? []) {
|
|
125
|
+
if (Boolean(declaration.important) === important) result.set(declaration.prop, declaration)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
107
129
|
}
|
|
108
130
|
return result
|
|
109
131
|
}
|
|
110
132
|
|
|
133
|
+
const selectorOf = (declaration, id) =>
|
|
134
|
+
declaration.parent.selectors.some(selector => selector.trim() === `#${id}`) ? `#${id}` : `.${id}`
|
|
135
|
+
|
|
111
136
|
/** 'vertical' or 'horizontal' when these declarations make a stack, else undefined. */
|
|
112
137
|
const directionOf = declarations => {
|
|
113
|
-
if (declarations.get('
|
|
138
|
+
if (declarations.get('display')?.value.trim() !== 'flex') return undefined
|
|
139
|
+
const wrap = declarations.get('flex-wrap')?.value.trim()
|
|
140
|
+
if (wrap !== undefined && wrap !== 'nowrap') return undefined
|
|
114
141
|
return /^column/.test(declarations.get('flex-direction')?.value.trim() ?? '') ? 'vertical' : 'horizontal'
|
|
115
142
|
}
|
|
116
143
|
|
|
@@ -135,12 +162,13 @@ export const stackChildrenPlugin = {
|
|
|
135
162
|
const parents = parentsIn(structurePath)
|
|
136
163
|
if (parents.size === 0) return
|
|
137
164
|
const byId = declarationsById(root)
|
|
165
|
+
const layoutById = declarationsById(root, { content: true })
|
|
138
166
|
|
|
139
167
|
const violations = new Set()
|
|
140
168
|
let first
|
|
141
169
|
for (const [child, parent] of parents) {
|
|
142
170
|
const childRules = byId.get(child)
|
|
143
|
-
const parentRules =
|
|
171
|
+
const parentRules = layoutById.get(parent)
|
|
144
172
|
if (childRules === undefined || parentRules === undefined) continue
|
|
145
173
|
for (const condition of new Set([BASE, ...parentRules.keys(), ...childRules.keys()])) {
|
|
146
174
|
const direction = directionOf(effective(parentRules, condition))
|
|
@@ -156,8 +184,8 @@ export const stackChildrenPlugin = {
|
|
|
156
184
|
if (!bad.length) continue
|
|
157
185
|
first ??= declaration.source
|
|
158
186
|
violations.add(
|
|
159
|
-
|
|
160
|
-
`${or(allowed.map(unit => LABELS[unit]))}; found ${bad.join(' ')}.`
|
|
187
|
+
`${selectorOf(declaration, child)}${where(declaration)}, a ${direction} stack child: ` +
|
|
188
|
+
`${declaration.prop} must be ${or(allowed.map(unit => LABELS[unit]))}; found ${bad.join(' ')}.`
|
|
161
189
|
)
|
|
162
190
|
}
|
|
163
191
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The item's structure file, for CSS plugins that check a stylesheet against its JSX tree: `structure.tsx` (or
|
|
2
2
|
// `.jsx`) next to the stylesheet, or one folder up when the stylesheet is the generated one in `_generated/`.
|
|
3
|
-
// Elements and rules meet on a literal `id` and `#id`.
|
|
3
|
+
// Elements and rules meet on a literal `id` and `#id` (or `.id`).
|
|
4
4
|
|
|
5
5
|
import { existsSync, readFileSync } from 'node:fs'
|
|
6
6
|
import { basename, dirname, join } from 'node:path'
|