ReviewOS

also looking at this

stacks/ts-css

chore(deps): update actions/cache action to v6

#29
Open renovate[bot] wants to merge renovate/actions-cache-6.x into main
9 files +68 -9

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/toolkit/src/engine/parser.tsmodified+14-0
Changes to packages/toolkit/src/engine/parser.ts
@@ -2267,6 +2267,14 @@ function extractCodeStringCandidates(content: string, bracketConfig?: BracketSyn
22672267 // payloads as code strings creates phantom utility classes and can make
22682268 // a classless fragment emit an entire preflight stylesheet.
22692269 if (markupAttribute) {
2270 // The one thing a prop value is allowed to name is an icon. A
2271 // component takes its glyph as an attribute (`<EmptyState icon="i-...">`),
2272 // and a rule that exists nowhere else on the page was never generated:
2273 // the icon rendered as an empty box. An icon token cannot be a CSRF
2274 // token, URL or v-html payload, and the generator only emits it when the
2275 // icon exists, so reading it creates no phantom rule.
2276 for (const token of literal.match(ICON_TOKEN) ?? [])
2277 tokens.add(token)
22702278 i = j
22712279 continue
22722280 }
@@ -2337,6 +2345,12 @@ function regexLiteralEnd(content: string, start: number): number {
23372345 return -1
23382346}
23392347
2348/**
2349 * `i-<collection>-<name>`, however it is spelled inside a markup attribute:
2350 * bare (`icon="i-lucide-x"`) or quoted inside a binding (`:icon="'i-lucide-x'"`).
2351 */
2352const ICON_TOKEN = /(?<![\w-])i-[a-z0-9]+(?:-[a-z0-9]+)+(?![\w-])/gi
2353
23402354function isMarkupAttributeString(content: string, quoteIndex: number): boolean {
23412355 const tagStart = content.lastIndexOf('<', quoteIndex)
23422356 const tagEnd = content.lastIndexOf('>', quoteIndex)
packages/toolkit/test/engine/code-strings.test.tsmodified+31-0
Changes to packages/toolkit/test/engine/code-strings.test.ts
@@ -246,3 +246,34 @@ describe('code-string extraction past comments and regexes', () => {
246246 expect(classes.has('gap-3')).toBe(true)
247247 })
248248})
249
250describe('icons named by a component prop', () => {
251 it('takes an icon class out of any attribute, not only class', () => {
252 const classes = extractClasses(`<MoreMenu icon="i-hugeicons-settings-02"><EmptyState icon="i-hugeicons-note-01" text="Nothing"/></MoreMenu>`)
253
254 expect(classes.has('i-hugeicons-settings-02')).toBe(true)
255 expect(classes.has('i-hugeicons-note-01')).toBe(true)
256 })
257
258 it('takes one quoted inside a binding', () => {
259 const classes = extractClasses(`<Row :icon="done ? 'i-hugeicons-tick-02' : 'i-hugeicons-circle'" />`)
260
261 expect(classes.has('i-hugeicons-tick-02')).toBe(true)
262 expect(classes.has('i-hugeicons-circle')).toBe(true)
263 })
264
265 it('still ignores every other attribute value', () => {
266 const classes = extractClasses(`<a href="/p/ab-cd-ef" data-token="abc-123-xyz" title="bg-red-500 shadow-lg">x</a>`)
267
268 expect(classes.has('ab-cd-ef')).toBe(false)
269 expect(classes.has('abc-123-xyz')).toBe(false)
270 expect(classes.has('bg-red-500')).toBe(false)
271 })
272
273 it('does not take a word that merely contains i-', () => {
274 const classes = extractClasses(`<a title="semi-colon wi-fi pi-day">x</a>`)
275
276 expect(classes.has('i-colon')).toBe(false)
277 expect(classes.has('fi')).toBe(false)
278 })
279})