Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@
"@volar/typescript": "2.4.26",
"@volar/vscode": "2.4.26",
"@vscode/vsce": "^3.2.1",
"@vue/compiler-sfc": "^3.5.0",
"@vue/compiler-sfc": "^3.5.24",
"@vue/language-core": "3.1.5",
"@vue/language-server": "3.1.5",
"@vue/typescript-plugin": "3.1.5",
Expand Down
1 change: 1 addition & 0 deletions packages/language-core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './lib/compilerOptions';
export * from './lib/languagePlugin';
export * from './lib/parsers/scriptSetupRanges';
export * from './lib/plugins';
export * from './lib/template/compile';
export * from './lib/types';
export * from './lib/utils/collectBindings';
export * from './lib/utils/forEachTemplateNode';
Expand Down
32 changes: 32 additions & 0 deletions packages/language-core/lib/codegen/template/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,38 @@ export function* generateElement(
ctx.currentComponent = currentComponent;
}

export function* generateFragment(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
node: CompilerDOM.ElementNode,
): Generator<Code> {
const [startTagOffset] = getElementTagOffsets(node, options.template);

// special case for <template v-for="..." :key="..." />
if (node.props.length) {
yield `__VLS_asFunctionalElement(__VLS_intrinsics.template)(`;
const token = yield* startBoundary('template', startTagOffset, codeFeatures.verification);
yield `{${newLine}`;
yield* generateElementProps(
options,
ctx,
node,
node.props,
options.vueCompilerOptions.checkUnknownProps,
);
yield `}`;
yield endBoundary(token, startTagOffset + node.tag.length);
yield `)${endOfLine}`;
}

const { currentComponent } = ctx;
ctx.currentComponent = undefined;
for (const child of node.children) {
yield* generateTemplateChild(options, ctx, child);
}
ctx.currentComponent = currentComponent;
}

function* generateFailedPropExps(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
Expand Down
11 changes: 7 additions & 4 deletions packages/language-core/lib/codegen/template/elementProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export function* generateElementProps(
}

const shouldSpread = propName === 'style' || propName === 'class';
const shouldCamelize = isComponent && getShouldCamelize(options, prop, propName);
const shouldCamelize = getShouldCamelize(options, node, prop, propName);
const features = getPropsCodeFeatures(strictPropsCheck);

if (shouldSpread) {
Expand Down Expand Up @@ -167,7 +167,7 @@ export function* generateElementProps(
}

const shouldSpread = prop.name === 'style' || prop.name === 'class';
const shouldCamelize = isComponent && getShouldCamelize(options, prop, prop.name);
const shouldCamelize = getShouldCamelize(options, node, prop, prop.name);
const features = getPropsCodeFeatures(strictPropsCheck);

if (shouldSpread) {
Expand Down Expand Up @@ -288,13 +288,16 @@ function* generateAttrValue(

function getShouldCamelize(
options: TemplateCodegenOptions,
node: CompilerDOM.ElementNode,
prop: CompilerDOM.AttributeNode | CompilerDOM.DirectiveNode,
propName: string,
) {
return (
node.tagType === CompilerDOM.ElementTypes.COMPONENT
|| node.tagType === CompilerDOM.ElementTypes.SLOT
) && (
prop.type !== CompilerDOM.NodeTypes.DIRECTIVE
|| !prop.arg
|| (prop.arg.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.isStatic)
|| prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.isStatic
)
&& hyphenateAttr(propName) === propName
&& !options.vueCompilerOptions.htmlAttributes.some(pattern => isMatch(propName, pattern));
Expand Down
37 changes: 10 additions & 27 deletions packages/language-core/lib/codegen/template/templateChild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { hyphenateTag } from '../../utils/shared';
import { codeFeatures } from '../codeFeatures';
import { endOfLine } from '../utils';
import type { TemplateCodegenContext } from './context';
import { generateComponent, generateElement } from './element';
import { generateComponent, generateElement, generateFragment } from './element';
import type { TemplateCodegenOptions } from './index';
import { generateInterpolation } from './interpolation';
import { generateSlotOutlet } from './slotOutlet';
Expand All @@ -17,16 +17,12 @@ export function* generateTemplateChild(
ctx: TemplateCodegenContext,
node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode | CompilerDOM.SimpleExpressionNode,
enterNode = true,
isVForChild = false,
): Generator<Code> {
if (enterNode && !ctx.enter(node)) {
return;
}

const cur = node as CompilerDOM.ElementNode | CompilerDOM.IfNode | CompilerDOM.ForNode;
if (cur.codegenNode?.type === CompilerDOM.NodeTypes.JS_CACHE_EXPRESSION) {
cur.codegenNode = cur.codegenNode.value as any;
}

if (node.type === CompilerDOM.NodeTypes.ROOT) {
for (const item of collectSingleRootNodes(options, node.children)) {
ctx.singleRootNodes.add(item);
Expand All @@ -40,33 +36,23 @@ export function* generateTemplateChild(
yield* generateSlotOutlet(options, ctx, node);
}
else {
const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as
| CompilerDOM.DirectiveNode
| undefined;
if (
node.tagType === CompilerDOM.ElementTypes.TEMPLATE
&& ctx.currentComponent
&& slotDir
) {
const slotDir = node.props.find(CompilerDOM.isVSlot);
if (node.tagType === CompilerDOM.ElementTypes.TEMPLATE && ctx.currentComponent && slotDir) {
yield* generateVSlot(options, ctx, node, slotDir);
}
else if (
node.tagType === CompilerDOM.ElementTypes.ELEMENT
|| node.tagType === CompilerDOM.ElementTypes.TEMPLATE
) {
yield* generateElement(options, ctx, node);
else if (node.tagType === CompilerDOM.ElementTypes.TEMPLATE && isVForChild) {
yield* generateFragment(options, ctx, node);
}
else {
else if (node.tagType === CompilerDOM.ElementTypes.COMPONENT) {
const { currentComponent } = ctx;
yield* generateComponent(options, ctx, node);
ctx.currentComponent = currentComponent;
}
else {
yield* generateElement(options, ctx, node);
}
}
}
else if (node.type === CompilerDOM.NodeTypes.TEXT_CALL) {
// {{ var }}
yield* generateTemplateChild(options, ctx, node.content, false);
}
else if (node.type === CompilerDOM.NodeTypes.COMPOUND_EXPRESSION) {
// {{ ... }} {{ ... }}
for (const child of node.children) {
Expand Down Expand Up @@ -98,9 +84,6 @@ export function* generateTemplateChild(
// v-for
yield* generateVFor(options, ctx, node);
}
else if (node.type === CompilerDOM.NodeTypes.TEXT) {
// not needed progress
}

if (enterNode) {
yield* ctx.exit();
Expand Down
36 changes: 2 additions & 34 deletions packages/language-core/lib/codegen/template/vFor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as CompilerDOM from '@vue/compiler-dom';
import type { Code } from '../../types';
import { collectBindingNames } from '../../utils/collectBindings';
import { codeFeatures } from '../codeFeatures';
import { endOfLine, getTypeScriptAST, newLine } from '../utils';
import { getTypeScriptAST, newLine } from '../utils';
import type { TemplateCodegenContext } from './context';
import type { TemplateCodegenOptions } from './index';
import { generateInterpolation } from './interpolation';
Expand Down Expand Up @@ -48,42 +48,10 @@ export function* generateVFor(
}
yield `) {${newLine}`;

let isFragment = true;
for (const argument of node.codegenNode?.children.arguments ?? []) {
if (
argument.type === CompilerDOM.NodeTypes.JS_FUNCTION_EXPRESSION
&& argument.returns?.type === CompilerDOM.NodeTypes.VNODE_CALL
&& argument.returns.props?.type === CompilerDOM.NodeTypes.JS_OBJECT_EXPRESSION
) {
if (argument.returns.tag !== CompilerDOM.FRAGMENT) {
isFragment = false;
continue;
}
for (const prop of argument.returns.props.properties) {
if (
prop.value.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
&& !prop.value.isStatic
) {
yield* generateInterpolation(
options,
ctx,
options.template,
codeFeatures.all,
prop.value.content,
prop.value.loc.start.offset,
`(`,
`)`,
);
yield endOfLine;
}
}
}
}

const { inVFor } = ctx;
ctx.inVFor = true;
for (const child of node.children) {
yield* generateTemplateChild(options, ctx, child, isFragment);
yield* generateTemplateChild(options, ctx, child, false, true);
}
ctx.inVFor = inVFor;

Expand Down
6 changes: 1 addition & 5 deletions packages/language-core/lib/codegen/template/vIf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ export function* generateVIf(
node: CompilerDOM.IfNode,
): Generator<Code> {
const originalBlockConditionsLength = ctx.blockConditions.length;
const isFragment = node.codegenNode
&& 'consequent' in node.codegenNode
&& 'tag' in node.codegenNode.consequent
&& node.codegenNode.consequent.tag === CompilerDOM.FRAGMENT;

for (let i = 0; i < node.branches.length; i++) {
const branch = node.branches[i]!;
Expand Down Expand Up @@ -53,7 +49,7 @@ export function* generateVIf(

yield `{${newLine}`;
for (const child of branch.children) {
yield* generateTemplateChild(options, ctx, child, i !== 0 || isFragment);
yield* generateTemplateChild(options, ctx, child, i !== 0, true);
}
yield `}${newLine}`;

Expand Down
2 changes: 2 additions & 0 deletions packages/language-core/lib/languagePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { forEachEmbeddedCode, type LanguagePlugin } from '@volar/language-core';
import * as CompilerDOM from '@vue/compiler-dom';
import type * as ts from 'typescript';
import * as LanguageCore from '../index';
import { createPlugins } from './plugins';
import type { VueCompilerOptions, VueLanguagePlugin, VueLanguagePluginReturn } from './types';
import { VueVirtualCode } from './virtualCode';
Expand Down Expand Up @@ -39,6 +40,7 @@ export function createVueLanguagePlugin<T>(
const pluginContext: Parameters<VueLanguagePlugin>[0] = {
modules: {
'@vue/compiler-dom': CompilerDOM,
'@vue/language-core': LanguageCore,
typescript: ts,
},
compilerOptions,
Expand Down
18 changes: 4 additions & 14 deletions packages/language-core/lib/plugins/vue-template-html.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type * as CompilerDOM from '@vue/compiler-dom';
import * as CompilerDOM from '@vue/compiler-dom';
import { compileTemplate } from '../template/compile';
import type { VueLanguagePlugin } from '../types';

interface Loc {
Expand All @@ -15,9 +16,7 @@ type Node =

const shouldAddSuffix = /(?<=<[^>/]+)$/;

const plugin: VueLanguagePlugin = ({ modules }) => {
const CompilerDOM = modules['@vue/compiler-dom'];

const plugin: VueLanguagePlugin = () => {
return {
version: 2.2,

Expand All @@ -31,11 +30,7 @@ const plugin: VueLanguagePlugin = ({ modules }) => {
addedSuffix = true;
}

const ast = CompilerDOM.parse(template, {
...options,
comments: true,
});
CompilerDOM.transform(ast, options);
const ast = compileTemplate(template, options);

return {
ast,
Expand Down Expand Up @@ -122,11 +117,6 @@ const plugin: VueLanguagePlugin = ({ modules }) => {
return false;
}
}
else if (node.type === CompilerDOM.NodeTypes.TEXT_CALL) {
if (!tryUpdateNode(node.content)) {
return false;
}
}
else if (node.type === CompilerDOM.NodeTypes.COMPOUND_EXPRESSION) {
for (const childNode of node.children) {
if (typeof childNode === 'object') {
Expand Down
4 changes: 0 additions & 4 deletions packages/language-core/lib/plugins/vue-template-inline-ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,6 @@ const plugin: VueLanguagePlugin = ({ modules: { typescript: ts } }) => {
visit(child);
}
}
else if (node.type === CompilerDOM.NodeTypes.TEXT_CALL) {
// {{ var }}
visit(node.content);
}
else if (node.type === CompilerDOM.NodeTypes.COMPOUND_EXPRESSION) {
// {{ ... }} {{ ... }}
for (const childNode of node.children) {
Expand Down
29 changes: 29 additions & 0 deletions packages/language-core/lib/template/compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { type CompilerOptions, getBaseTransformPreset, parse, transform } from '@vue/compiler-dom';
import { transformElement } from './transforms/transformElement';
import { transformText } from './transforms/transformText';
import { transformFor } from './transforms/vFor';
import { transformIf } from './transforms/vIf';

export function compileTemplate(source: string, options: CompilerOptions) {
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset();
const resolvedOptions: CompilerOptions = {
...options,
comments: true,
nodeTransforms: [
nodeTransforms[0]!, // transformVBindShorthand
transformIf,
transformFor,
transformElement,
transformText,
...options.nodeTransforms || [],
],
directiveTransforms: {
...directiveTransforms,
...options.directiveTransforms,
},
};

const ast = parse(source, resolvedOptions);
transform(ast, resolvedOptions);
return ast;
}
Loading
Loading