Skip to content

Commit f242e85

Browse files
authored
fix(language-core): escape \ and ' in className avoid type error (#4619)
1 parent dc6f943 commit f242e85

File tree

2 files changed

+59
-6
lines changed
  • packages/language-core/lib/codegen/template
  • test-workspace/tsc/vue3/#4537

2 files changed

+59
-6
lines changed

packages/language-core/lib/codegen/template/index.ts

+42-6
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,9 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
9999
ctx.codeFeatures.navigationWithoutRename,
100100
];
101101
yield `'`;
102-
yield [
103-
className,
104-
'template',
105-
offset,
106-
ctx.codeFeatures.navigationAndAdditionalCompletion,
107-
];
102+
103+
// fix https://github.com/vuejs/language-tools/issues/4537
104+
yield* escapeString(className, offset, ['\\', '\'']);
108105
yield `'`;
109106
yield [
110107
'',
@@ -136,6 +133,45 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
136133
}
137134
yield endOfLine;
138135
}
136+
137+
function* escapeString(className: string, offset: number, escapeTargets: string[]): Generator<Code> {
138+
let count = 0;
139+
140+
const currentEscapeTargets = [...escapeTargets];
141+
const firstEscapeTarget = currentEscapeTargets.shift()!;
142+
const splitted = className.split(firstEscapeTarget);
143+
144+
for (let i = 0; i < splitted.length; i++) {
145+
const part = splitted[i];
146+
const partLength = part.length;
147+
148+
if (escapeTargets.length > 0) {
149+
yield* escapeString(part, offset + count, [...currentEscapeTargets]);
150+
} else {
151+
yield [
152+
part,
153+
'template',
154+
offset + count,
155+
ctx.codeFeatures.navigationAndAdditionalCompletion,
156+
];
157+
}
158+
159+
if (i !== splitted.length - 1) {
160+
yield '\\';
161+
162+
yield [
163+
firstEscapeTarget,
164+
'template',
165+
offset + count + partLength,
166+
ctx.codeFeatures.navigationAndAdditionalCompletion,
167+
];
168+
169+
count += partLength + 1;
170+
} else {
171+
count += partLength;
172+
}
173+
}
174+
}
139175
}
140176

141177
export function* forEachElementNode(node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode): Generator<CompilerDOM.ElementNode> {
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script setup lang="ts" generic="T">
2+
defineProps<{
3+
type: T;
4+
}>();
5+
6+
defineModel<boolean>({ required: true });
7+
</script>
8+
9+
<template>
10+
<div class="['radio']"></div>
11+
</template>
12+
13+
<style>
14+
.\[\'radio\'\] {
15+
color: red
16+
}
17+
</style>

0 commit comments

Comments
 (0)