@teleporthq/teleport-plugin-css 0.44.0-alpha.0 → 0.44.0
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/__tests__/component-scoped.ts +4 -2
- package/__tests__/referenced-styles.ts +61 -0
- package/__tests__/selector-paren-sanitize.ts +69 -0
- package/dist/cjs/index.d.ts +9 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +510 -48
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/style-sheet.d.ts.map +1 -1
- package/dist/cjs/style-sheet.js +8 -2
- package/dist/cjs/style-sheet.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +11 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +125 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/index.d.ts +9 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +512 -50
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/style-sheet.d.ts.map +1 -1
- package/dist/esm/style-sheet.js +9 -3
- package/dist/esm/style-sheet.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +11 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +120 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +5 -5
- package/src/index.ts +663 -64
- package/src/style-sheet.ts +10 -4
- package/src/utils.ts +132 -0
package/src/style-sheet.ts
CHANGED
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
ChunkType,
|
|
6
6
|
FileType,
|
|
7
7
|
} from '@teleporthq/teleport-types'
|
|
8
|
-
import { join
|
|
8
|
+
import { join } from 'path'
|
|
9
|
+
import { GenericUtils } from '@teleporthq/teleport-shared'
|
|
10
|
+
import { sanitizeStylesheetSelectors } from './utils'
|
|
9
11
|
|
|
10
12
|
interface StyleSheetPlugin {
|
|
11
13
|
fileName?: string
|
|
@@ -64,7 +66,7 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
|
|
|
64
66
|
|
|
65
67
|
const fontPath = relativeFontPath
|
|
66
68
|
? join(
|
|
67
|
-
|
|
69
|
+
GenericUtils.localRelativePath(join(...(uidl.outputOptions?.folderPath || [])), './'),
|
|
68
70
|
join(fontsFolder || '', font.path)
|
|
69
71
|
)
|
|
70
72
|
: join('/', assetIdentifier || '', 'fonts', font.path)
|
|
@@ -93,7 +95,7 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
|
|
|
93
95
|
styleSetDefinitions,
|
|
94
96
|
cssMap,
|
|
95
97
|
mediaStylesMap,
|
|
96
|
-
(styleName
|
|
98
|
+
(styleName) => styleName
|
|
97
99
|
)
|
|
98
100
|
}
|
|
99
101
|
|
|
@@ -107,7 +109,11 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
|
|
|
107
109
|
name: fileName,
|
|
108
110
|
type: ChunkType.STRING,
|
|
109
111
|
fileType: FileType.CSS,
|
|
110
|
-
|
|
112
|
+
// Repair unbalanced selector parens before emitting — a stray `)` in a
|
|
113
|
+
// single AI-authored selector otherwise breaks the consumer's production
|
|
114
|
+
// `next build` (cssnano selector parser: "Expected an opening parenthesis"),
|
|
115
|
+
// while `next dev` silently tolerates it.
|
|
116
|
+
content: sanitizeStylesheetSelectors(cssMap.join('\n \n')),
|
|
111
117
|
linkAfter: [],
|
|
112
118
|
})
|
|
113
119
|
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { ASTUtils } from '@teleporthq/teleport-plugin-common'
|
|
2
|
+
import { PluginCSS, UIDLConditionExpressionEntry, UIDLPropDefinition } from '@teleporthq/teleport-types'
|
|
3
|
+
|
|
4
|
+
export const createConditionalStatement = (
|
|
5
|
+
conditions: UIDLConditionExpressionEntry[],
|
|
6
|
+
leftOperand: UIDLPropDefinition['defaultValue']
|
|
7
|
+
) => {
|
|
8
|
+
return conditions.map((condition) => {
|
|
9
|
+
const { operation, operand } = condition
|
|
10
|
+
|
|
11
|
+
if (operand === undefined) {
|
|
12
|
+
return `${ASTUtils.convertToUnaryOperator(operation)}${getValueType(operand)}`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return `${getValueType(leftOperand)} ${ASTUtils.convertToBinaryOperator(
|
|
16
|
+
operation
|
|
17
|
+
)} ${getValueType(operand)}`
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Balance parentheses inside a single CSS selector "prelude" (the text before a
|
|
23
|
+
* `{`). Drops unmatched `)` and closes unmatched `(`, while leaving quoted
|
|
24
|
+
* strings untouched. Valid balanced parens (`:not(.x)`, `:nth-child(2n+1)`,
|
|
25
|
+
* attribute values containing `)`) are preserved byte-for-byte.
|
|
26
|
+
*/
|
|
27
|
+
const balanceSelectorParens = (prelude: string): string => {
|
|
28
|
+
let depth = 0
|
|
29
|
+
let out = ''
|
|
30
|
+
let quote: string | null = null
|
|
31
|
+
for (let i = 0; i < prelude.length; i++) {
|
|
32
|
+
const ch = prelude[i]
|
|
33
|
+
// A backslash escapes the next char (e.g. an escaped `\(` / `\)` inside a
|
|
34
|
+
// class name) — copy both verbatim so escaped parens are never counted.
|
|
35
|
+
if (ch === '\\' && i + 1 < prelude.length) {
|
|
36
|
+
out += ch + prelude[i + 1]
|
|
37
|
+
i++
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
if (quote) {
|
|
41
|
+
out += ch
|
|
42
|
+
if (ch === quote) {
|
|
43
|
+
quote = null
|
|
44
|
+
}
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
if (ch === '"' || ch === "'") {
|
|
48
|
+
quote = ch
|
|
49
|
+
out += ch
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
if (ch === '(') {
|
|
53
|
+
depth++
|
|
54
|
+
out += ch
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
if (ch === ')') {
|
|
58
|
+
if (depth === 0) {
|
|
59
|
+
// Unmatched closing paren — drop it. A stray `)` in a selector makes the
|
|
60
|
+
// production cssnano selector parser throw "Expected an opening
|
|
61
|
+
// parenthesis", failing the whole `next build` even though dev tolerates it.
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
depth--
|
|
65
|
+
out += ch
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
out += ch
|
|
69
|
+
}
|
|
70
|
+
if (depth > 0) {
|
|
71
|
+
out += ')'.repeat(depth)
|
|
72
|
+
}
|
|
73
|
+
return out
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Repairs unbalanced parentheses in every selector of a generated stylesheet so a
|
|
78
|
+
* single malformed AI-authored selector (e.g. `.card:hover) { … }`) can't break
|
|
79
|
+
* the consumer's production build. Only selector preludes (text immediately
|
|
80
|
+
* before each `{`) are touched; declaration blocks and quoted strings are left
|
|
81
|
+
* exactly as-is. Idempotent and a no-op for well-formed CSS.
|
|
82
|
+
*/
|
|
83
|
+
export const sanitizeStylesheetSelectors = (css: string): string => {
|
|
84
|
+
let out = ''
|
|
85
|
+
let segStart = 0
|
|
86
|
+
let quote: string | null = null
|
|
87
|
+
for (let i = 0; i < css.length; i++) {
|
|
88
|
+
const ch = css[i]
|
|
89
|
+
if (ch === '\\') {
|
|
90
|
+
// Skip the escaped char so an escaped `\{` / `\}` / `\"` is never read as a
|
|
91
|
+
// block boundary or quote delimiter.
|
|
92
|
+
i++
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
if (quote) {
|
|
96
|
+
if (ch === quote) {
|
|
97
|
+
quote = null
|
|
98
|
+
}
|
|
99
|
+
continue
|
|
100
|
+
}
|
|
101
|
+
if (ch === '"' || ch === "'") {
|
|
102
|
+
quote = ch
|
|
103
|
+
continue
|
|
104
|
+
}
|
|
105
|
+
if (ch === '{') {
|
|
106
|
+
out += balanceSelectorParens(css.slice(segStart, i)) + ch
|
|
107
|
+
segStart = i + 1
|
|
108
|
+
} else if (ch === '}') {
|
|
109
|
+
out += css.slice(segStart, i) + ch
|
|
110
|
+
segStart = i + 1
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
out += css.slice(segStart)
|
|
114
|
+
return out
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const getValueType = (value: UIDLPropDefinition['defaultValue']) => {
|
|
118
|
+
const valueType = typeof value
|
|
119
|
+
switch (valueType) {
|
|
120
|
+
case 'string':
|
|
121
|
+
return `"${value}"`
|
|
122
|
+
case 'number':
|
|
123
|
+
return value
|
|
124
|
+
case 'boolean':
|
|
125
|
+
return value
|
|
126
|
+
default:
|
|
127
|
+
throw new PluginCSS(
|
|
128
|
+
`Conditional node received an operand of type ${valueType} \n
|
|
129
|
+
Received ${JSON.stringify(value)}`
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|