Skip to content

Commit 6c4fee6

Browse files
committed
chore: wip
1 parent 63abf29 commit 6c4fee6

File tree

2 files changed

+44
-37
lines changed

2 files changed

+44
-37
lines changed

packages/pickier/src/format.ts

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,23 @@ function makeIndent(visualLevels: number, cfg: PickierConfig): string {
2828
}
2929

3030
function convertDoubleToSingle(str: string): string {
31-
// strip surrounding quotes
31+
// strip surrounding quotes: "xyz" → xyz
3232
const inner = str.slice(1, -1)
33-
// unescape escaped double quotes, keep other escapes intact
34-
const unescaped = inner.replace(/\\"/g, '"')
35-
// escape single quotes that aren't already escaped
36-
const escapedSingles = unescaped.replace(/(?<!\\)'/g, '\\\'')
37-
return `'${escapedSingles}'`
33+
// Strategy: swap quote types for cleaner output
34+
// Unescape escaped double quotes: \" → "
35+
// Swap single quotes to double quotes: ' → " (since they're literals in the string)
36+
let result = inner.replace(/\\"/g, '"') // unescape \"
37+
result = result.replace(/'/g, '"') // swap ' to "
38+
return `'${result}'`
3839
}
3940

4041
function convertSingleToDouble(str: string): string {
4142
const inner = str.slice(1, -1)
42-
const unescaped = inner.replace(/\\'/g, '\'')
43-
const escapedDoubles = unescaped.replace(/"/g, '\\"')
44-
return `"${escapedDoubles}"`
43+
// Unescape escaped single quotes: \' → '
44+
// Swap double quotes to single quotes: " → '
45+
let result = inner.replace(/\\'/g, '\'')
46+
result = result.replace(/"/g, '\'')
47+
return `"${result}"`
4548
}
4649

4750
function fixQuotes(content: string, preferred: 'single' | 'double', filePath: string): string {
@@ -56,26 +59,11 @@ function fixQuotes(content: string, preferred: 'single' | 'double', filePath: st
5659
let output = ''
5760
let i = 0
5861
let inString: 'single' | 'double' | 'template' | null = null
59-
let escaped = false
6062
let stringStart = 0
6163

6264
while (i < line.length) {
6365
const ch = line[i]
6466

65-
if (escaped) {
66-
output += ch
67-
escaped = false
68-
i++
69-
continue
70-
}
71-
72-
if (ch === '\\' && inString) {
73-
escaped = true
74-
output += ch
75-
i++
76-
continue
77-
}
78-
7967
// Check for string boundaries
8068
if (!inString) {
8169
if (ch === '"') {
@@ -100,8 +88,17 @@ function fixQuotes(content: string, preferred: 'single' | 'double', filePath: st
10088
i++
10189
}
10290
else {
103-
// Inside a string - check if we're exiting
104-
if ((inString === 'double' && ch === '"') || (inString === 'single' && ch === '\'')) {
91+
// Inside a string - check if we're exiting (but not if escaped)
92+
// Count consecutive backslashes before this position
93+
let backslashCount = 0
94+
let j = i - 1
95+
while (j >= 0 && line[j] === '\\') {
96+
backslashCount++
97+
j--
98+
}
99+
const isEscaped = backslashCount % 2 === 1
100+
101+
if (!isEscaped && ((inString === 'double' && ch === '"') || (inString === 'single' && ch === '\''))) {
105102
// Found closing quote - convert if needed
106103
const stringContent = line.slice(stringStart + 1, i)
107104
if (inString === 'double' && preferred === 'single') {
@@ -120,14 +117,14 @@ function fixQuotes(content: string, preferred: 'single' | 'double', filePath: st
120117
i++
121118
continue
122119
}
123-
if (inString === 'template' && ch === '`') {
120+
if (!isEscaped && inString === 'template' && ch === '`') {
124121
// Template literal end
125122
output += ch
126123
inString = null
127124
i++
128125
continue
129126
}
130-
// Still inside string, buffer it
127+
// Still inside string, continue scanning
131128
i++
132129
}
133130
}

packages/pickier/src/linter.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,17 @@ export async function runLintProgrammatic(
237237
fixed = next.join('\n')
238238
}
239239
fixed = applyPluginFixes(file, fixed, cfg)
240-
if (!options.dryRun && fixed !== src) {
241-
writeFileSync(file, fixed, 'utf8')
242-
// OPTIMIZATION: Only re-scan if content actually changed
240+
241+
// If content changed, re-scan the fixed version
242+
if (fixed !== src) {
243243
const newSuppress = parseDisableDirectives(fixed)
244244
const newCommentLines = getCommentLines(fixed)
245245
issues = scanContentOptimized(file, fixed, cfg, newSuppress, newCommentLines)
246+
247+
// Write file only if not dry-run
248+
if (!options.dryRun) {
249+
writeFileSync(file, fixed, 'utf8')
250+
}
246251
}
247252
}
248253

@@ -1356,16 +1361,21 @@ export async function runLint(globs: string[], options: LintOptions): Promise<nu
13561361
}
13571362
// Apply plugin rule fixers only (no global formatting in lint --fix)
13581363
fixed = applyPluginFixes(file, fixed, cfg)
1359-
if (!options.dryRun && fixed !== src) {
1360-
writeFileSync(file, fixed, 'utf8')
1361-
// OPTIMIZATION: Only re-scan if content actually changed
1364+
1365+
// If content changed, re-scan the fixed version
1366+
if (fixed !== src) {
13621367
const newSuppress = parseDisableDirectives(fixed)
13631368
const newCommentLines = getCommentLines(fixed)
13641369
issues = scanContentOptimized(file, fixed, cfg, newSuppress, newCommentLines)
1365-
}
13661370

1367-
if (options.dryRun && src !== fixed && (options.verbose !== undefined ? options.verbose : cfg.verbose)) {
1368-
logger.debug(colors.gray(`dry-run: would apply fixes in ${relative(process.cwd(), file)}`))
1371+
// Write file only if not dry-run
1372+
if (!options.dryRun) {
1373+
writeFileSync(file, fixed, 'utf8')
1374+
}
1375+
1376+
if (options.dryRun && (options.verbose !== undefined ? options.verbose : cfg.verbose)) {
1377+
logger.debug(colors.gray(`dry-run: would apply fixes in ${relative(process.cwd(), file)}`))
1378+
}
13691379
}
13701380
}
13711381

0 commit comments

Comments
 (0)