@wix/origami-transforms 0.1.9 → 0.1.11
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.11",
|
|
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": "b2340e8ef9e2e52ae323397986026dcf38f3cd9a3a69fdc64a1e6736"
|
|
58
58
|
}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
// Resolves a component's custom enums at build time. A site sets only the enum's value on an instance,
|
|
2
2
|
// `#comp-1 { --labelAlign: center }`, and this writes the vars that option applies in its place, from the
|
|
3
3
|
// `@custom-enum` blocks in the component wrapper's `custom-enums.css` (see component-wrapper-server's
|
|
4
|
-
// `customEnums.ts`),
|
|
4
|
+
// `customEnums.ts`), read from the wrapper's folder: the item's JSX imports the wrapper's CSS, so the blocks aren't in
|
|
5
|
+
// the stylesheet. A stylesheet that `@import`s the wrapper's CSS has them inlined; those are used and removed.
|
|
5
6
|
// Native `if()` can't do it: Firefox doesn't have it, and a var named like its key refers to itself.
|
|
6
7
|
//
|
|
7
8
|
// The instance's component comes from the item's structure file (structureFile.js): the element with
|
|
8
9
|
// `id="comp-1"`, and the `@origami-wrappers/…` import it is rendered from. See customEnums.md.
|
|
9
10
|
|
|
10
|
-
import { realpathSync } from 'node:fs'
|
|
11
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
11
12
|
import { createRequire } from 'node:module'
|
|
12
|
-
import { basename, dirname } from 'node:path'
|
|
13
|
+
import { basename, dirname, join } from 'node:path'
|
|
13
14
|
import postcss from 'postcss'
|
|
14
15
|
import { LayoutError } from '../transform/layoutError.js'
|
|
15
16
|
import { literalIdOf, parseStructure, structureFileOf, walk } from './structureFile.js'
|
|
16
17
|
|
|
18
|
+
const CUSTOM_ENUMS_CSS = 'custom-enums.css'
|
|
17
19
|
// `@origami-wrappers/<module>/<symbol>`, and nothing that could resolve outside its package.
|
|
18
20
|
const WRAPPER_IMPORT = /^@origami-wrappers\/[\w-]+\/[\w-]+$/
|
|
19
21
|
// `#id` or `.id` (exports give an instance both), then only what narrows that same element: classes,
|
|
@@ -49,10 +51,10 @@ const real = path => {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
/**
|
|
52
|
-
* Id → the enums of every wrapper instance; none for one whose component has no custom enums.
|
|
53
|
-
*
|
|
54
|
+
* Id → the enums of every wrapper instance; none for one whose component has no custom enums. `enumsOf` gives a
|
|
55
|
+
* wrapper folder's enums.
|
|
54
56
|
*/
|
|
55
|
-
const enumsById = (structurePath,
|
|
57
|
+
const enumsById = (structurePath, enumsOf) => {
|
|
56
58
|
const require = createRequire(structurePath)
|
|
57
59
|
const byId = new Map()
|
|
58
60
|
for (const [id, source] of importsById(structurePath)) {
|
|
@@ -62,7 +64,7 @@ const enumsById = (structurePath, byFolder) => {
|
|
|
62
64
|
} catch {
|
|
63
65
|
folder = undefined
|
|
64
66
|
}
|
|
65
|
-
byId.set(id,
|
|
67
|
+
byId.set(id, folder === undefined ? [] : enumsOf(folder))
|
|
66
68
|
}
|
|
67
69
|
return byId
|
|
68
70
|
}
|
|
@@ -89,7 +91,7 @@ const fromDependency = declaration => declaration.source?.input.file?.split(/[\\
|
|
|
89
91
|
|
|
90
92
|
/**
|
|
91
93
|
* The `@custom-enum` blocks in the stylesheet: wrapper folder → its enums, with each option as the enum's full var
|
|
92
|
-
* set; the blocks themselves
|
|
94
|
+
* set; the blocks themselves; and the ones that can't be read.
|
|
93
95
|
*
|
|
94
96
|
* A block sits in its element's rule, `.menu`, or `.menu .menu-input` for an inline element. A var an option doesn't
|
|
95
97
|
* set has the default option's value, or `inherit` when the default doesn't set it either, which is what an instance
|
|
@@ -188,17 +190,42 @@ const inlineRule = (declaration, instance, { inline, editorSelector }, options,
|
|
|
188
190
|
inserted.set(outer, node)
|
|
189
191
|
}
|
|
190
192
|
|
|
193
|
+
/** Removes the stylesheet's `@custom-enum` blocks, which only this plugin reads. */
|
|
194
|
+
export const removeCustomEnums = root =>
|
|
195
|
+
root.walkAtRules('custom-enum', block => {
|
|
196
|
+
if (block.parent) block.parent.raws.semicolon = true
|
|
197
|
+
block.remove()
|
|
198
|
+
})
|
|
199
|
+
|
|
191
200
|
/** @type {import('../transform/types.js').CssTransformPlugin} */
|
|
192
201
|
export const customEnumsPlugin = {
|
|
193
202
|
name: 'custom-enums',
|
|
194
203
|
// After mixins copy their bodies in, before presets and layout move declarations out of the instance's rule.
|
|
195
204
|
order: 11,
|
|
196
205
|
transform(root, context) {
|
|
197
|
-
const
|
|
198
|
-
if (blocks.length === 0) return
|
|
206
|
+
const inlined = definitionsIn(root)
|
|
199
207
|
const structurePath = structureFileOf(context.filePath)
|
|
208
|
+
if (structurePath === undefined && inlined.blocks.length === 0) return
|
|
200
209
|
if (structurePath !== undefined) context.addDependency?.(structurePath)
|
|
201
|
-
const
|
|
210
|
+
const malformed = [...inlined.malformed]
|
|
211
|
+
// A wrapper's enums are the blocks inlined from its folder, or else those in the folder's custom-enums.css.
|
|
212
|
+
const readFolders = new Map()
|
|
213
|
+
const enumsOf = folder => {
|
|
214
|
+
if (inlined.byFolder.has(folder)) return inlined.byFolder.get(folder)
|
|
215
|
+
if (!readFolders.has(folder)) {
|
|
216
|
+
const file = join(folder, CUSTOM_ENUMS_CSS)
|
|
217
|
+
let enums = []
|
|
218
|
+
if (existsSync(file)) {
|
|
219
|
+
context.addDependency?.(file)
|
|
220
|
+
const definitions = definitionsIn(postcss.parse(readFileSync(file, 'utf8'), { from: file }))
|
|
221
|
+
malformed.push(...definitions.malformed)
|
|
222
|
+
enums = definitions.byFolder.get(folder) ?? []
|
|
223
|
+
}
|
|
224
|
+
readFolders.set(folder, enums)
|
|
225
|
+
}
|
|
226
|
+
return readFolders.get(folder)
|
|
227
|
+
}
|
|
228
|
+
const instances = structurePath === undefined ? new Map() : enumsById(structurePath, enumsOf)
|
|
202
229
|
const keys = new Set([...instances.values()].flatMap(enums => enums.map(({ key }) => key)))
|
|
203
230
|
|
|
204
231
|
/** @type {import('postcss').Declaration[]} */
|
|
@@ -282,10 +309,7 @@ export const customEnumsPlugin = {
|
|
|
282
309
|
})
|
|
283
310
|
}
|
|
284
311
|
|
|
285
|
-
|
|
286
|
-
if (block.parent) block.parent.raws.semicolon = true
|
|
287
|
-
block.remove()
|
|
288
|
-
}
|
|
312
|
+
removeCustomEnums(root)
|
|
289
313
|
|
|
290
314
|
// A rule with a selector list is split, one rule per selector, so each instance gets its own option.
|
|
291
315
|
for (const rule of new Set(declarations.map(ruleOf))) {
|
|
@@ -57,15 +57,17 @@ the defaults:
|
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
The
|
|
61
|
-
the
|
|
62
|
-
them from the
|
|
60
|
+
The item's JSX imports each used wrapper's `defaults.css`, which imports this file, so the browser loads
|
|
61
|
+
it ahead of the site's stylesheets, and the blocks are not in the document the plugin gets. The plugin reads
|
|
62
|
+
them from the wrapper's folder instead. The CSS stage removes them from the wrapper's own CSS, which runs no
|
|
63
|
+
other plugin; browsers would ignore the unknown at-rule anyway, and the defaults still apply. A stylesheet
|
|
64
|
+
that `@import`s `defaults.css` has the blocks inlined: the plugin reads those and removes them from the output.
|
|
63
65
|
An inline element's block sits in `{editor selector} {inline selector}` (`.menu .menu-input`).
|
|
64
66
|
|
|
65
67
|
The item's structure file (next to the stylesheet, or one folder up for `_generated/`) says which
|
|
66
68
|
component each `id` is: the element `<Menu id="comp-1" />` and its `@origami-wrappers/…` import. The
|
|
67
|
-
import resolves to the wrapper's folder, and
|
|
68
|
-
declares the structure file, so editing
|
|
69
|
+
import resolves to the wrapper's folder, and that folder's `custom-enums.css` holds its enums. The plugin
|
|
70
|
+
declares the structure file and each `custom-enums.css` it reads, so editing either re-runs the stylesheet.
|
|
69
71
|
|
|
70
72
|
Each option is written as the full set of the enum's vars: the default's value wherever the option itself is
|
|
71
73
|
silent, or `inherit` when the default is silent too (what an instance that picks no option gets). So a mobile
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Fails the build on an Image whose `uri` is not a Wix media ID, such as a web URL or a local file.
|
|
2
|
-
// The Wix import accepts such a `uri` but the image is broken on the site; `origami upload-media`
|
|
2
|
+
// The Wix import accepts such a `uri` but the image is broken on the site; `wix origami upload-media`
|
|
3
3
|
// uploads it and points the Image at the uploaded file. `yarn dev` only warns, so the page still
|
|
4
4
|
// previews. Like the layout rules, Image is identified by its JSX tag name, and a computed `uri` is
|
|
5
5
|
// not checked.
|
|
@@ -34,7 +34,7 @@ export const mediaValidationPlugin = {
|
|
|
34
34
|
const id = attributes.find(attribute => attribute.name.name === 'id')?.value?.value
|
|
35
35
|
const line = uri.loc?.start.line
|
|
36
36
|
violations.push(
|
|
37
|
-
`${file}${line ? `:${line}` : ''} <Image${id ? ` id="${id}"` : ''}> image.uri "${uri.value.value}" is not a Wix media ID. Run \`origami upload-media\` to upload it.`
|
|
37
|
+
`${file}${line ? `:${line}` : ''} <Image${id ? ` id="${id}"` : ''}> image.uri "${uri.value.value}" is not a Wix media ID. Run \`wix origami upload-media\` to upload it.`
|
|
38
38
|
)
|
|
39
39
|
first ??= { file: context.filePath, line, column: uri.loc?.start.column }
|
|
40
40
|
},
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// stylesheet the plugins see is the whole page: a rule declared in one carrier and a rule that
|
|
9
9
|
// depends on it in another arrive in the same document.
|
|
10
10
|
|
|
11
|
+
import { removeCustomEnums } from '../../cssPlugins/customEnums.js'
|
|
11
12
|
import { runCssPlugins } from './runPlugins.js'
|
|
12
13
|
|
|
13
14
|
const DEPENDENCY_DIRECTORY = 'node_modules/'
|
|
@@ -34,7 +35,12 @@ export const createCssPostcssPlugin = ({ selectPlugins, contextFor, failures })
|
|
|
34
35
|
if (from === undefined) return
|
|
35
36
|
|
|
36
37
|
const fileContext = contextFor(from)
|
|
37
|
-
|
|
38
|
+
// A dependency's stylesheet runs no plugins. It only loses a wrapper's `@custom-enum` blocks, which the
|
|
39
|
+
// custom-enums plugin reads from the wrapper's folder and browsers would skip.
|
|
40
|
+
if (!isSiteOwned(fileContext.relativePath)) {
|
|
41
|
+
removeCustomEnums(root)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
38
44
|
|
|
39
45
|
const plugins = selectPlugins(fileContext)
|
|
40
46
|
if (!plugins.length) return
|