Skip to content

Commit 4283b25

Browse files
committed
refactor(packages): fix eslint issues and continue migration modularization
1 parent a9efa50 commit 4283b25

34 files changed

Lines changed: 506 additions & 237 deletions

packages/config/src/defaults.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function getDefaultTransformerConfig(): TransformerOptions {
3232
include: defaultPipelineInclude,
3333
exclude: defaultPipelineExclude,
3434
},
35-
disabled: process.env['NODE_ENV'] === 'development',
35+
disabled: process.env.NODE_ENV === 'development',
3636
registry: {
3737
file: '.tw-patch/tw-class-list.json',
3838
mapping: {

packages/config/test/defaults.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('defaults', () => {
4040
})
4141

4242
it('getDefaultTransformerConfig reflects NODE_ENV', () => {
43-
const originalEnv = process.env['NODE_ENV']
43+
const originalEnv = process.env.NODE_ENV
4444

4545
vi.stubEnv('NODE_ENV', 'development')
4646
expect(getDefaultTransformerConfig().disabled).toBe(true)
@@ -51,10 +51,10 @@ describe('defaults', () => {
5151
vi.unstubAllEnvs()
5252

5353
if (originalEnv !== undefined) {
54-
process.env['NODE_ENV'] = originalEnv
54+
process.env.NODE_ENV = originalEnv
5555
}
5656
else {
57-
delete process.env['NODE_ENV']
57+
delete process.env.NODE_ENV
5858
}
5959
})
6060
})

packages/core/src/ctx/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export class Context {
174174
}
175175
}
176176
catch (error) {
177-
console.error(`[tailwindcss-mangle]: ${error}`)
177+
process.stderr.write(`[tailwindcss-mangle]: ${String(error)}\n`)
178178
}
179179
}
180180
}

packages/core/src/svelte/index.ts

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,6 @@ import { makeRegex, splitCode } from '../shared'
77

88
interface ISvelteHandlerOptions extends IJsHandlerOptions {}
99

10-
export async function svelteHandler(
11-
rawSource: string,
12-
options: ISvelteHandlerOptions,
13-
): Promise<IHandlerTransformResult> {
14-
const { ctx, id } = options
15-
const ms = new MagicString(rawSource)
16-
17-
try {
18-
const ast = parse(rawSource, {
19-
filename: id || 'unknown.svelte',
20-
})
21-
22-
// Process the AST for class attributes and directives
23-
await processSvelteAst(ast, ms, ctx, id)
24-
25-
return {
26-
code: ms.toString(),
27-
get map() {
28-
return ms.generateMap()
29-
},
30-
}
31-
}
32-
catch (error) {
33-
// Fallback to jsHandler if Svelte parsing fails
34-
return jsHandler(rawSource, options)
35-
}
36-
}
37-
3810
async function processSvelteAst(
3911
ast: any,
4012
ms: MagicString,
@@ -46,7 +18,9 @@ async function processSvelteAst(
4618

4719
// Walk the AST and process class-related nodes
4820
async function walk(node: any) {
49-
if (!node) { return }
21+
if (!node) {
22+
return
23+
}
5024

5125
// Handle regular class attributes
5226
if (node.type === 'Attribute' && node.name === 'class') {
@@ -134,3 +108,31 @@ async function processSvelteAst(
134108
// Wait for all style transformations to complete
135109
await Promise.all(stylePromises)
136110
}
111+
112+
export async function svelteHandler(
113+
rawSource: string,
114+
options: ISvelteHandlerOptions,
115+
): Promise<IHandlerTransformResult> {
116+
const { ctx, id } = options
117+
const ms = new MagicString(rawSource)
118+
119+
try {
120+
const ast = parse(rawSource, {
121+
filename: id || 'unknown.svelte',
122+
})
123+
124+
// Process the AST for class attributes and directives
125+
await processSvelteAst(ast, ms, ctx, id)
126+
127+
return {
128+
code: ms.toString(),
129+
get map() {
130+
return ms.generateMap()
131+
},
132+
}
133+
}
134+
catch {
135+
// Fallback to jsHandler if Svelte parsing fails
136+
return jsHandler(rawSource, options)
137+
}
138+
}

packages/core/src/vue/index.ts

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,6 @@ interface IVueHandlerOptions extends IJsHandlerOptions {
99
preserveScoped?: boolean
1010
}
1111

12-
export async function vueHandler(
13-
rawSource: string,
14-
options: IVueHandlerOptions,
15-
): Promise<IHandlerTransformResult> {
16-
const { ctx, id } = options
17-
const ms = new MagicString(rawSource)
18-
19-
try {
20-
const { descriptor } = parse(rawSource, {
21-
filename: id || 'unknown.vue',
22-
})
23-
24-
// Process template section
25-
if (descriptor.template) {
26-
await processTemplate(descriptor.template, ms, ctx, id)
27-
}
28-
29-
// Process script section
30-
if (descriptor.script || descriptor.scriptSetup) {
31-
await processScript(descriptor, ms, ctx, id)
32-
}
33-
34-
// Process style sections
35-
if (descriptor.styles && descriptor.styles.length > 0) {
36-
await processStyles(descriptor.styles, ms, ctx, id)
37-
}
38-
39-
return {
40-
code: ms.toString(),
41-
get map() {
42-
return ms.generateMap()
43-
},
44-
}
45-
}
46-
catch (error) {
47-
// Fallback to jsHandler if Vue parsing fails
48-
return jsHandler(rawSource, options)
49-
}
50-
}
51-
5212
async function processTemplate(
5313
template: any,
5414
ms: MagicString,
@@ -59,7 +19,7 @@ async function processTemplate(
5919

6020
if (!template.ast) {
6121
try {
62-
const compiled = compileTemplate({
22+
compileTemplate({
6323
source: template.content,
6424
filename: id || 'unknown.vue',
6525
id: `${id || 'unknown'}?template`,
@@ -74,7 +34,6 @@ async function processTemplate(
7434

7535
// Process static class attributes in template
7636
const classAttrRegex = /\sclass\s*=\s*["']([^"']+)["']/g
77-
let match
7837

7938
// We need to search within the template section
8039
const templateStart = template.loc.start.offset
@@ -83,7 +42,7 @@ async function processTemplate(
8342

8443
const replacements: Array<{ start: number, end: number, value: string }> = []
8544

86-
while ((match = classAttrRegex.exec(templateContent)) !== null) {
45+
for (const match of templateContent.matchAll(classAttrRegex)) {
8746
const fullMatch = match[0]
8847
const classValue = match[1]
8948
if (classValue === undefined) {
@@ -129,7 +88,9 @@ async function processScript(
12988
id?: string,
13089
): Promise<void> {
13190
const script = descriptor.scriptSetup || descriptor.script
132-
if (!script) { return }
91+
if (!script) {
92+
return
93+
}
13394

13495
const scriptContent = ms.original.slice(
13596
script.loc.start.offset,
@@ -173,3 +134,43 @@ async function processStyles(
173134
}
174135
}
175136
}
137+
138+
export async function vueHandler(
139+
rawSource: string,
140+
options: IVueHandlerOptions,
141+
): Promise<IHandlerTransformResult> {
142+
const { ctx, id } = options
143+
const ms = new MagicString(rawSource)
144+
145+
try {
146+
const { descriptor } = parse(rawSource, {
147+
filename: id || 'unknown.vue',
148+
})
149+
150+
// Process template section
151+
if (descriptor.template) {
152+
await processTemplate(descriptor.template, ms, ctx, id)
153+
}
154+
155+
// Process script section
156+
if (descriptor.script || descriptor.scriptSetup) {
157+
await processScript(descriptor, ms, ctx, id)
158+
}
159+
160+
// Process style sections
161+
if (descriptor.styles && descriptor.styles.length > 0) {
162+
await processStyles(descriptor.styles, ms, ctx, id)
163+
}
164+
165+
return {
166+
code: ms.toString(),
167+
get map() {
168+
return ms.generateMap()
169+
},
170+
}
171+
}
172+
catch {
173+
// Fallback to jsHandler if Vue parsing fails
174+
return jsHandler(rawSource, options)
175+
}
176+
}

packages/core/test/utils/index.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,15 @@ function escapeClassName(value: string) {
1313
function extractClassTokens(source: string) {
1414
const tokens = new Set<string>()
1515
const attrPattern = /(class|className)=(["'`])([^"'`]+)\2/g
16-
let match: RegExpExecArray | null
17-
while ((match = attrPattern.exec(source))) {
16+
for (const match of source.matchAll(attrPattern)) {
1817
match[3].split(/\s+/).filter(Boolean).forEach(token => tokens.add(token))
1918
}
2019

2120
const classListPattern = /classList\.add\(([^)]+)\)/g
22-
while ((match = classListPattern.exec(source))) {
21+
for (const match of source.matchAll(classListPattern)) {
2322
const inner = match[1]
2423
const stringPattern = /(["'`])([^"'`]+)\1/g
25-
let strMatch: RegExpExecArray | null
26-
while ((strMatch = stringPattern.exec(inner))) {
24+
for (const strMatch of inner.matchAll(stringPattern)) {
2725
strMatch[2].split(/\s+/).filter(Boolean).forEach(token => tokens.add(token))
2826
}
2927
}

packages/core/test/utils/svelte-to-tsx.ts

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,52 @@
1-
/* eslint-disable @typescript-eslint/no-unused-vars */
1+
function extractTagContentsAndRemove(source: string, tagName: string) {
2+
const openToken = `<${tagName}`
3+
const closeToken = `</${tagName}>`
4+
const contents: string[] = []
5+
let output = ''
6+
let cursor = 0
27

3-
import MagicString from 'magic-string'
8+
while (cursor < source.length) {
9+
const openIndex = source.indexOf(openToken, cursor)
10+
if (openIndex < 0) {
11+
output += source.slice(cursor)
12+
break
13+
}
414

5-
/** @see https://github.com/sveltejs/svelte/blob/d3297e2a2595db08c85356d65fd5f953b04a681f/packages/svelte/src/compiler/preprocess/index.js#L255C1-L255C85 */
6-
const regex_style_tags = /<!--[\s\S]*?-->|<style(\s[\s\S]*?)?(?:>([\s\S]*?)<\/style>|\/>)/gi
15+
output += source.slice(cursor, openIndex)
16+
const tagEndIndex = source.indexOf('>', openIndex)
17+
if (tagEndIndex < 0) {
18+
output += source.slice(openIndex)
19+
break
20+
}
721

8-
/** @see https://github.com/sveltejs/svelte/blob/d3297e2a2595db08c85356d65fd5f953b04a681f/packages/svelte/src/compiler/preprocess/index.js#L256C1-L256C88 */
9-
const regex_script_tags = /<!--[\s\S]*?-->|<script(\s[\s\S]*?)?(?:>([\s\S]*?)<\/script>|\/>)/gi
22+
const isSelfClosing = source[tagEndIndex - 1] === '/'
23+
if (isSelfClosing) {
24+
cursor = tagEndIndex + 1
25+
continue
26+
}
1027

11-
export function svelteToTsx(code: string) {
12-
try {
13-
const scripts = []
14-
const original = new MagicString(code)
15-
16-
// Remove script tags & extract script content
17-
let match: RegExpExecArray | null
18-
while ((match = regex_script_tags.exec(code)) != null) {
19-
const [fullMatch, _attributesStr, scriptContent] = match
20-
if (scriptContent) {
21-
scripts.push(scriptContent)
22-
original.remove(match.index, match.index + fullMatch.length)
23-
}
28+
const closeIndex = source.indexOf(closeToken, tagEndIndex + 1)
29+
if (closeIndex < 0) {
30+
output += source.slice(openIndex)
31+
break
2432
}
2533

26-
const templateContent = original.toString().trimStart().replaceAll(regex_style_tags, '').replaceAll(regex_style_tags, '')
27-
const transformed = `${scripts.join('')}\nconst render = <div>${templateContent}</div>`
34+
contents.push(source.slice(tagEndIndex + 1, closeIndex))
35+
cursor = closeIndex + closeToken.length
36+
}
37+
38+
return { contents, source: output }
39+
}
40+
41+
function removeTagBlocks(source: string, tagName: string) {
42+
return extractTagContentsAndRemove(source, tagName).source
43+
}
2844

29-
return transformed.toString().trim()
45+
export function svelteToTsx(code: string) {
46+
try {
47+
const { contents: scripts, source: withoutScripts } = extractTagContentsAndRemove(code, 'script')
48+
const templateContent = removeTagBlocks(withoutScripts, 'style').trimStart()
49+
return `${scripts.join('')}\nconst render = <div>${templateContent}</div>`.trim()
3050
}
3151
catch {
3252
return ''

packages/core/test/utils/vue-to-tsx.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,17 @@ export function vueToTsx(code: string) {
5252
// recursion-free traversal
5353
while (stack.length > 0) {
5454
const node = stack.pop()
55-
if (!node) { continue }
55+
if (!node) {
56+
continue
57+
}
5658

5759
if (node.type === NodeTypes.ELEMENT) {
5860
node.props.forEach((element) => {
5961
rewriteProp(element)
6062
})
61-
for (const child of node.children) { stack.push(child) }
63+
for (const child of node.children) {
64+
stack.push(child)
65+
}
6266
}
6367
}
6468

packages/shared/src/classGenerator.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { IClassGenerator, IClassGeneratorContextItem, IClassGeneratorOptions } from './types'
22

3+
import process from 'node:process'
34
import { acceptChars, regExpTest, stripEscapeSequence } from './utils'
45

56
export class ClassGenerator implements IClassGenerator {
@@ -84,13 +85,13 @@ export class ClassGenerator implements IClassGenerator {
8485

8586
if (opts.reserveClassName && regExpTest(opts.reserveClassName, newClassName)) {
8687
if (opts.log) {
87-
console.log(`The class name has been reserved. ${newClassName}`)
88+
process.stdout.write(`The class name has been reserved. ${newClassName}\n`)
8889
}
8990
this.newClassSize++
9091
return this.generateClassName(original)
9192
}
9293
if (opts.log) {
93-
console.log(`Minify class name from ${original} to ${newClassName}`)
94+
process.stdout.write(`Minify class name from ${original} to ${newClassName}\n`)
9495
}
9596
const newClass: IClassGeneratorContextItem = {
9697
name: newClassName,

packages/shared/test/classGenerator.behavior.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('ClassGenerator behaviour', () => {
4444

4545
const first = generator.generateClassName('foo')
4646
expect(first.name).toBe('foo-1')
47-
expect(generator.context['foo']).toBe(1)
47+
expect(generator.context.foo).toBe(1)
4848

4949
const again = generator.generateClassName('foo')
5050
expect(again).toBe(first)

0 commit comments

Comments
 (0)