@pyreon/styler 0.24.4 → 0.24.6

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.
Files changed (47) hide show
  1. package/package.json +5 -7
  2. package/src/ThemeProvider.ts +0 -65
  3. package/src/__tests__/ThemeProvider.test.ts +0 -67
  4. package/src/__tests__/benchmark.bench.ts +0 -200
  5. package/src/__tests__/composition-chain.test.ts +0 -537
  6. package/src/__tests__/css.test.ts +0 -70
  7. package/src/__tests__/dev-gate-treeshake.test.ts +0 -85
  8. package/src/__tests__/forward.test.ts +0 -282
  9. package/src/__tests__/globalStyle.test.ts +0 -72
  10. package/src/__tests__/hash.test.ts +0 -70
  11. package/src/__tests__/hybrid-injection.test.ts +0 -225
  12. package/src/__tests__/index.ts +0 -14
  13. package/src/__tests__/inject-rules.browser.test.ts +0 -40
  14. package/src/__tests__/insertion-effect.test.ts +0 -119
  15. package/src/__tests__/integration-dom.test.ts +0 -58
  16. package/src/__tests__/integration.test.ts +0 -179
  17. package/src/__tests__/keyframes.test.ts +0 -68
  18. package/src/__tests__/memory-growth.test.ts +0 -220
  19. package/src/__tests__/native-marker.test.ts +0 -9
  20. package/src/__tests__/p3-features.test.ts +0 -316
  21. package/src/__tests__/resolve-cache.test.ts +0 -94
  22. package/src/__tests__/resolve.test.ts +0 -308
  23. package/src/__tests__/shared.test.ts +0 -133
  24. package/src/__tests__/sheet-advanced.test.ts +0 -659
  25. package/src/__tests__/sheet-split-atrules.test.ts +0 -410
  26. package/src/__tests__/sheet.test.ts +0 -250
  27. package/src/__tests__/static-styler-resolve-cost.test.ts +0 -160
  28. package/src/__tests__/styled-reactive.test.ts +0 -74
  29. package/src/__tests__/styled-ssr.test.ts +0 -75
  30. package/src/__tests__/styled.test.ts +0 -511
  31. package/src/__tests__/styler.browser.test.tsx +0 -194
  32. package/src/__tests__/theme.test.ts +0 -33
  33. package/src/__tests__/useCSS.test.ts +0 -172
  34. package/src/css.ts +0 -13
  35. package/src/env.d.ts +0 -6
  36. package/src/forward.ts +0 -308
  37. package/src/globalStyle.ts +0 -53
  38. package/src/hash.ts +0 -28
  39. package/src/index.ts +0 -15
  40. package/src/keyframes.ts +0 -36
  41. package/src/manifest.ts +0 -332
  42. package/src/resolve.ts +0 -225
  43. package/src/shared.ts +0 -22
  44. package/src/sheet.ts +0 -635
  45. package/src/styled.tsx +0 -503
  46. package/src/tests/manifest-snapshot.test.ts +0 -51
  47. package/src/useCSS.ts +0 -20
@@ -1,308 +0,0 @@
1
- import { describe, expect, it } from "vitest"
2
- import { css } from "../css"
3
- import { CSSResult, normalizeCSS, resolve, resolveValue } from "../resolve"
4
- import { isDynamic } from "../shared"
5
-
6
- // Helper to create a TemplateStringsArray
7
- const tsa = (strings: readonly string[]): TemplateStringsArray => {
8
- const arr = [...strings] as string[] & { raw: readonly string[] }
9
- arr.raw = strings
10
- return arr
11
- }
12
-
13
- describe("resolve", () => {
14
- describe("primitive interpolations", () => {
15
- it("resolves strings", () => {
16
- const result = resolve(tsa(["color: ", ";"]), ["red"], {})
17
- expect(result).toBe("color: red;")
18
- })
19
-
20
- it("resolves numbers", () => {
21
- const result = resolve(tsa(["flex: ", ";"]), [1], {})
22
- expect(result).toBe("flex: 1;")
23
- })
24
-
25
- it("resolves null as empty string", () => {
26
- const result = resolve(tsa(["a", "b"]), [null], {})
27
- expect(result).toBe("ab")
28
- })
29
-
30
- it("resolves undefined as empty string", () => {
31
- const result = resolve(tsa(["a", "b"]), [undefined], {})
32
- expect(result).toBe("ab")
33
- })
34
-
35
- it("resolves false as empty string", () => {
36
- const result = resolve(tsa(["a", "b"]), [false], {})
37
- expect(result).toBe("ab")
38
- })
39
-
40
- it("resolves true as empty string", () => {
41
- const result = resolve(tsa(["a", "b"]), [true], {})
42
- expect(result).toBe("ab")
43
- })
44
- })
45
-
46
- describe("function interpolations", () => {
47
- it("calls functions with props and uses return value", () => {
48
- const fn = (props: Record<string, unknown>) => props.color as string
49
- const result = resolve(tsa(["color: ", ";"]), [fn], { color: "blue" })
50
- expect(result).toBe("color: blue;")
51
- })
52
-
53
- it("resolves nested function results recursively", () => {
54
- const fn = () => () => "red"
55
- const result = resolve(tsa(["color: ", ";"]), [fn], {})
56
- expect(result).toBe("color: red;")
57
- })
58
-
59
- it("handles functions returning null", () => {
60
- const fn = () => null
61
- const result = resolve(tsa(["a", "b"]), [fn], {})
62
- expect(result).toBe("ab")
63
- })
64
-
65
- it("handles functions returning false (conditional)", () => {
66
- const fn = (props: Record<string, unknown>) => (props.active ? "color: red;" : false)
67
- const result = resolve(tsa(["", ""]), [fn], { active: false })
68
- expect(result).toBe("")
69
- })
70
-
71
- it("uses empty object when no props provided", () => {
72
- const fn = (props: Record<string, unknown>) =>
73
- Object.keys(props).length === 0 ? "empty" : "has-props"
74
- const result = resolve(tsa(["", ""]), [fn], {})
75
- expect(result).toBe("empty")
76
- })
77
- })
78
-
79
- describe("CSSResult interpolations", () => {
80
- it("resolves nested CSSResult", () => {
81
- const inner = css`color: red;`
82
- const result = resolveValue(inner, {})
83
- expect(result).toBe("color: red;")
84
- })
85
-
86
- it("resolves deeply nested CSSResults", () => {
87
- const inner1 = css`color: red;`
88
- const inner2 = css`${inner1} display: flex;`
89
- const result = resolveValue(inner2, {})
90
- expect(result).toBe("color: red; display: flex;")
91
- })
92
-
93
- it("resolves CSSResult with function interpolations", () => {
94
- const inner = css`color: ${((p: Record<string, unknown>) => p.color) as any};`
95
- const result = resolveValue(inner, { color: "green" })
96
- expect(result).toBe("color: green;")
97
- })
98
- })
99
-
100
- describe("array interpolations", () => {
101
- it("resolves arrays of values", () => {
102
- const result = resolve(tsa(["", ""]), [["a", "b", "c"]], {})
103
- expect(result).toBe("abc")
104
- })
105
-
106
- it("resolves arrays with CSSResults", () => {
107
- const inner = css`color: red;`
108
- const result = resolveValue([inner, " display: flex;"], {})
109
- expect(result).toBe("color: red; display: flex;")
110
- })
111
- })
112
-
113
- describe("combined patterns", () => {
114
- it("handles multiple interpolation types", () => {
115
- const result = resolve(
116
- tsa(["display: ", "; color: ", "; flex: ", ";"]),
117
- ["flex", "red", 1],
118
- {},
119
- )
120
- expect(result).toBe("display: flex; color: red; flex: 1;")
121
- })
122
-
123
- it("handles conditional CSS with logical AND (truthy)", () => {
124
- const condition = true
125
- const conditionalCss = condition && css`color: red;`
126
- const result = resolveValue(conditionalCss, {})
127
- expect(result).toBe("color: red;")
128
- })
129
-
130
- it("handles conditional CSS with logical AND (falsy)", () => {
131
- const condition = false
132
- const conditionalCss = condition && css`color: red;`
133
- const result = resolveValue(conditionalCss, {})
134
- expect(result).toBe("")
135
- })
136
- })
137
- })
138
-
139
- describe("CSSResult", () => {
140
- it("stores strings and values as readonly properties", () => {
141
- const strings = ["color: ", ";"] as unknown as TemplateStringsArray
142
- const values = ["red"]
143
- const result = new CSSResult(strings, values)
144
- expect(result.strings).toBe(strings)
145
- expect(result.values).toBe(values)
146
- })
147
-
148
- it("toString resolves with empty props", () => {
149
- const result = css`color: red;`
150
- expect(result.toString()).toBe("color: red;")
151
- })
152
- })
153
-
154
- describe("normalizeCSS", () => {
155
- describe("comment stripping", () => {
156
- it("strips CSS block comments", () => {
157
- expect(normalizeCSS("/* comment */ color: red;")).toBe("color: red;")
158
- })
159
-
160
- it("strips multiple block comments", () => {
161
- expect(normalizeCSS("/* BASE */ color: red; /* HOVER */ font-size: 1rem;")).toBe(
162
- "color: red; font-size: 1rem;",
163
- )
164
- })
165
-
166
- it("strips multiline block comments", () => {
167
- expect(normalizeCSS("/* --------\n BASE STATE\n -------- */\nheight: 3rem;")).toBe(
168
- "height: 3rem;",
169
- )
170
- })
171
-
172
- it("strips JS-style line comments", () => {
173
- expect(normalizeCSS("// this is not valid CSS\ncolor: red;")).toBe("color: red;")
174
- })
175
-
176
- it("preserves :// in URLs", () => {
177
- expect(normalizeCSS("background: url(https://example.com/img.png);")).toContain(
178
- "https://example.com/img.png",
179
- )
180
- })
181
-
182
- it("strips line comments but preserves URL protocols", () => {
183
- const result = normalizeCSS("// comment\nbackground: url(https://example.com/img.png);")
184
- expect(result).toContain("https://example.com/img.png")
185
- expect(result).not.toContain("// comment")
186
- })
187
-
188
- it("handles unterminated block comment", () => {
189
- expect(normalizeCSS("color: red; /* never closed")).toBe("color: red;")
190
- })
191
-
192
- it("handles unterminated line comment", () => {
193
- expect(normalizeCSS("color: red;\n// trailing comment")).toBe("color: red;")
194
- })
195
- })
196
-
197
- describe("whitespace handling", () => {
198
- it("collapses whitespace", () => {
199
- expect(normalizeCSS(" color: red; font-size: 1rem; ")).toBe(
200
- "color: red; font-size: 1rem;",
201
- )
202
- })
203
-
204
- it("converts tabs and newlines to spaces", () => {
205
- expect(normalizeCSS("color:\tred;\nfont-size:\t1rem;")).toBe("color: red; font-size: 1rem;")
206
- })
207
-
208
- it("collapses multiple spaces", () => {
209
- expect(normalizeCSS("color: red;")).toBe("color: red;")
210
- })
211
-
212
- it("trims leading and trailing whitespace", () => {
213
- expect(normalizeCSS(" color: red; ")).toBe("color: red;")
214
- })
215
-
216
- it("handles carriage returns", () => {
217
- expect(normalizeCSS("color: red;\r\nfont-size: 1rem;")).toBe("color: red; font-size: 1rem;")
218
- })
219
- })
220
-
221
- describe("semicolon handling", () => {
222
- it("removes redundant semicolons after {", () => {
223
- expect(normalizeCSS(".foo {; color: red; }")).toBe(".foo { color: red; }")
224
- })
225
-
226
- it("removes redundant semicolons after }", () => {
227
- expect(normalizeCSS(".foo { color: red; }; .bar { }")).toBe(".foo { color: red; } .bar { }")
228
- })
229
- })
230
-
231
- describe("edge cases", () => {
232
- it("returns empty string for empty input", () => {
233
- expect(normalizeCSS("")).toBe("")
234
- })
235
-
236
- it("returns empty string for whitespace-only input", () => {
237
- expect(normalizeCSS(" \n\t ")).toBe("")
238
- })
239
-
240
- it("handles CSS with braces", () => {
241
- expect(normalizeCSS(".foo { color: red; }")).toBe(".foo { color: red; }")
242
- })
243
-
244
- it("handles @media rules", () => {
245
- const result = normalizeCSS("@media (min-width: 48em) { color: blue; }")
246
- expect(result).toContain("@media")
247
- expect(result).toContain("color: blue;")
248
- })
249
- })
250
- })
251
-
252
- // Behavioural lock-in for the CSSResult._staticResolved cache (ported from
253
- // vitus-labs `754cd203` + lock-in `60fc25c1`). Common pattern: a shared
254
- // static snippet interpolated into many dynamic components. Without this
255
- // cache the snippet's resolve work was paid once per dynamic render of
256
- // every consumer; with it, the resolve fires once per snippet, total.
257
- describe("CSSResult._staticResolved cache", () => {
258
- it("populates _staticResolved on first resolveValue of a known-static CSSResult", () => {
259
- const inner = css`color: red;`
260
- // Pre-classify as static via isDynamic (the same call shared.ts makes
261
- // at styled-component creation time).
262
- isDynamic(inner)
263
- expect(inner._isDynamic).toBe(false)
264
- expect(inner._staticResolved).toBe(undefined)
265
-
266
- resolveValue(inner, {})
267
- expect(inner._staticResolved).toBe("color: red;")
268
- })
269
-
270
- it("returns cached _staticResolved on subsequent resolveValue calls", () => {
271
- const inner = css`padding: 12px;`
272
- isDynamic(inner)
273
- resolveValue(inner, {})
274
- expect(inner._staticResolved).toBe("padding: 12px;")
275
-
276
- // Mutate values to a sentinel that would change the resolved output if
277
- // recomputed. The cache MUST return the prior result.
278
- ;(inner as unknown as { values: unknown[] }).values = ["SENTINEL"]
279
- expect(resolveValue(inner, {})).toBe("padding: 12px;")
280
- })
281
-
282
- it("does NOT cache dynamic CSSResults (props vary per call)", () => {
283
- const dyn = css`color: ${(p: Record<string, unknown>) => p.c as string};`
284
- isDynamic(dyn)
285
- expect(dyn._isDynamic).toBe(true)
286
-
287
- // Resolve twice with different props; cache should not be populated.
288
- resolveValue(dyn, { c: "red" })
289
- expect(dyn._staticResolved).toBe(undefined)
290
- resolveValue(dyn, { c: "blue" })
291
- expect(dyn._staticResolved).toBe(undefined)
292
- })
293
-
294
- it("skips cache when _isDynamic is undefined (not yet classified)", () => {
295
- // Construct a CSSResult directly without going through isDynamic.
296
- // resolveValue's cache check is `_isDynamic === false` (strict), so an
297
- // unclassified CSSResult falls through to the regular resolve path
298
- // — the regular path takes the SECOND branch (`return resolve(...)`)
299
- // and does NOT populate the cache.
300
- const tpl = Object.assign(["color: ", ";"], {
301
- raw: ["color: ", ";"],
302
- }) as unknown as TemplateStringsArray
303
- const r = new CSSResult(tpl, ["red"])
304
- expect(r._isDynamic).toBe(undefined)
305
- expect(resolveValue(r, {})).toBe("color: red;")
306
- expect(r._staticResolved).toBe(undefined) // cache stays unpopulated
307
- })
308
- })
@@ -1,133 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { css } from '../css'
3
- import { CSSResult } from '../resolve'
4
- import { isDynamic } from '../shared'
5
-
6
- describe('isDynamic', () => {
7
- it('returns true for function values', () => {
8
- expect(isDynamic(() => 'red')).toBe(true)
9
- })
10
-
11
- it('returns false for string values', () => {
12
- expect(isDynamic('color: red;')).toBe(false)
13
- })
14
-
15
- it('returns false for number values', () => {
16
- expect(isDynamic(42)).toBe(false)
17
- })
18
-
19
- it('returns false for null and undefined', () => {
20
- expect(isDynamic(null)).toBe(false)
21
- expect(isDynamic(undefined)).toBe(false)
22
- })
23
-
24
- it('returns false for boolean values', () => {
25
- expect(isDynamic(true)).toBe(false)
26
- expect(isDynamic(false)).toBe(false)
27
- })
28
-
29
- it('returns true for arrays containing functions', () => {
30
- expect(isDynamic(['a', () => 'b'])).toBe(true)
31
- })
32
-
33
- it('returns false for arrays of static values', () => {
34
- expect(isDynamic(['a', 'b', 42])).toBe(false)
35
- })
36
-
37
- it('returns true for CSSResult with dynamic values', () => {
38
- const result = css`
39
- color: ${() => 'red'};
40
- `
41
- expect(isDynamic(result)).toBe(true)
42
- })
43
-
44
- it('returns false for CSSResult with only static values', () => {
45
- const result = css`
46
- color: ${'red'};
47
- `
48
- expect(isDynamic(result)).toBe(false)
49
- })
50
-
51
- it('returns true for nested dynamic CSSResult', () => {
52
- const inner = css`
53
- color: ${() => 'red'};
54
- `
55
- const outer = css`
56
- ${inner}
57
- `
58
- expect(isDynamic(outer)).toBe(true)
59
- })
60
-
61
- it('returns false for nested static CSSResult', () => {
62
- const inner = css`
63
- color: red;
64
- `
65
- const outer = css`
66
- ${inner}
67
- `
68
- expect(isDynamic(outer)).toBe(false)
69
- })
70
-
71
- it('detects deeply nested dynamic values', () => {
72
- const deep = css`
73
- color: ${() => 'red'};
74
- `
75
- const mid = css`
76
- ${deep}
77
- `
78
- const outer = css`
79
- ${mid}
80
- `
81
- expect(isDynamic(outer)).toBe(true)
82
- })
83
-
84
- it('handles arrays inside CSSResult', () => {
85
- const result = new CSSResult(
86
- Object.assign(['', ''], { raw: ['', ''] }) as TemplateStringsArray,
87
- [['a', () => 'b']],
88
- )
89
- expect(isDynamic(result)).toBe(true)
90
- })
91
-
92
- // Behavioural lock-in for the CSSResult._isDynamic memoization (ported
93
- // from vitus-labs `c483cabc` + lock-in `60fc25c1`). Without these tests
94
- // a future regression that removed the cache would only show up as a
95
- // perf regression, never as a test failure.
96
- describe('CSSResult _isDynamic memoization', () => {
97
- it('populates _isDynamic on first call for dynamic templates', () => {
98
- const r = css`color: ${() => 'red'};`
99
- expect(r._isDynamic).toBe(undefined)
100
- isDynamic(r)
101
- expect(r._isDynamic).toBe(true)
102
- })
103
-
104
- it('populates _isDynamic on first call for static templates', () => {
105
- const r = css`color: ${'red'};`
106
- expect(r._isDynamic).toBe(undefined)
107
- isDynamic(r)
108
- expect(r._isDynamic).toBe(false)
109
- })
110
-
111
- it('returns cached result on subsequent calls without rescanning values', () => {
112
- const r = css`color: ${() => 'red'};`
113
- const first = isDynamic(r)
114
- expect(first).toBe(true)
115
- expect(r._isDynamic).toBe(true)
116
-
117
- // Mutate values to a sentinel that would invert the answer if rescanned.
118
- // The memoized path must NOT consult `values` again — it should return
119
- // the cached `_isDynamic` directly.
120
- ;(r as unknown as { values: unknown[] }).values = ['static-only']
121
- expect(isDynamic(r)).toBe(true) // still uses cached value, not rescan
122
- })
123
-
124
- it('memoizes nested CSSResults independently', () => {
125
- const inner = css`color: ${() => 'red'};`
126
- const outer = css`${inner}`
127
- isDynamic(outer)
128
- // Recursing through outer populates inner too.
129
- expect(inner._isDynamic).toBe(true)
130
- expect(outer._isDynamic).toBe(true)
131
- })
132
- })
133
- })