Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/vuejs/language-tools into…
Browse files Browse the repository at this point in the history
… fix/repeated-ast-parsing
  • Loading branch information
KazariEX committed Dec 31, 2024
2 parents 0fdf8ac + 7eafbb2 commit 4fcbfa4
Show file tree
Hide file tree
Showing 24 changed files with 391 additions and 381 deletions.
5 changes: 3 additions & 2 deletions packages/language-core/lib/codegen/globalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_unknownDirective = (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
type __VLS_WithComponent<N0 extends string, LocalComponents, N1 extends string, N2 extends string, N3 extends string> =
type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
N3 extends keyof LocalComponents ? N3 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N3] } :
Self extends object ? { [K in N0]: Self } :
N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N1] } :
N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } :
N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } :
Expand Down Expand Up @@ -143,7 +144,7 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: (_: {}${strictTemplates ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${strictTemplates ? '' : ' & Record<string, unknown>'} } };
function __VLS_elementAsFunction<T>(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (_: T${strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S;
function __VLS_tryAsConstant<const T>(t: T): T;
Expand Down
1 change: 1 addition & 0 deletions packages/language-core/lib/codegen/script/scriptSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ function* generateMacros(
ctx: ScriptCodegenContext
): Generator<Code> {
if (options.vueCompilerOptions.target >= 3.3) {
yield `// @ts-ignore${newLine}`;
yield `declare const { `;
for (const macro of Object.keys(options.vueCompilerOptions.macros)) {
if (!ctx.bindingNames.has(macro)) {
Expand Down
28 changes: 5 additions & 23 deletions packages/language-core/lib/codegen/script/template.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as path from 'path-browserify';
import type { Code } from '../../types';
import { getSlotsPropertyName, hyphenateTag } from '../../utils/shared';
import { hyphenateTag } from '../../utils/shared';
import { TemplateCodegenContext, createTemplateCodegenContext } from '../template/context';
import { generateInterpolation } from '../template/interpolation';
import { generateStyleScopedClassReferences } from '../template/styleScopedClasses';
Expand Down Expand Up @@ -69,23 +68,6 @@ function* generateTemplateComponents(options: ScriptCodegenOptions): Generator<C
types.push(`typeof __VLS_componentsOption`);
}

let nameType: Code | undefined;
if (options.sfc.script && options.scriptRanges?.exportDefault?.nameOption) {
const { nameOption } = options.scriptRanges.exportDefault;
nameType = options.sfc.script.content.slice(nameOption.start, nameOption.end);
}
else if (options.sfc.scriptSetup) {
const baseName = path.basename(options.fileName);
nameType = `'${options.scriptSetupRanges?.defineOptions?.name ?? baseName.slice(0, baseName.lastIndexOf('.'))}'`;
}
if (nameType) {
types.push(
`{ [K in ${nameType}]: typeof __VLS_self & (new () => { `
+ getSlotsPropertyName(options.vueCompilerOptions.target)
+ `: typeof ${options.scriptSetupRanges?.defineSlots?.name ?? `__VLS_slots`} }) }`
);
}

types.push(`typeof __VLS_ctx`);

yield `type __VLS_LocalComponents =`;
Expand Down Expand Up @@ -145,15 +127,15 @@ function* generateTemplateBody(
yield `const __VLS_slots = {}${endOfLine}`;
}
yield `const __VLS_inheritedAttrs = {}${endOfLine}`;
yield `const $refs = {}${endOfLine}`;
yield `const $el = {} as any${endOfLine}`;
yield `const __VLS_refs = {}${endOfLine}`;
yield `const __VLS_rootEl = {} as any${endOfLine}`;
}

yield `return {${newLine}`;
yield ` attrs: {} as Partial<typeof __VLS_inheritedAttrs>,${newLine}`;
yield ` slots: ${options.scriptSetupRanges?.defineSlots?.name ?? '__VLS_slots'},${newLine}`;
yield ` refs: $refs,${newLine}`;
yield ` rootEl: $el,${newLine}`;
yield ` refs: __VLS_refs,${newLine}`;
yield ` rootEl: __VLS_rootEl,${newLine}`;
yield `}${endOfLine}`;
}

Expand Down
5 changes: 2 additions & 3 deletions packages/language-core/lib/codegen/template/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
},
});
const localVars = new Map<string, number>();
const specialVars = new Set<string>();
const accessExternalVariables = new Map<string, Set<number>>();
const slots: {
name: string;
Expand All @@ -115,7 +116,6 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
expVar: string;
varName: string;
}[] = [];
const hasSlotElements = new Set<CompilerDOM.ElementNode>();;
const blockConditions: string[] = [];
const scopedClasses: {
source: string;
Expand All @@ -132,9 +132,9 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
slots,
dynamicSlots,
codeFeatures,
specialVars,
accessExternalVariables,
lastGenericComment,
hasSlotElements,
blockConditions,
scopedClasses,
emptyClassOffsets,
Expand All @@ -144,7 +144,6 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
inheritedAttrVars,
templateRefs,
currentComponent: undefined as {
node: CompilerDOM.ElementNode;
ctxVar: string;
used: boolean;
} | undefined,
Expand Down
168 changes: 36 additions & 132 deletions packages/language-core/lib/codegen/template/element.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as CompilerDOM from '@vue/compiler-dom';
import { camelize, capitalize } from '@vue/shared';
import type { Code, VueCodeInformation } from '../../types';
import { hyphenateTag } from '../../utils/shared';
import { getSlotsPropertyName, hyphenateTag } from '../../utils/shared';
import { createVBindShorthandInlayHintInfo } from '../inlayHints';
import { collectVars, createTsAst, endOfLine, newLine, normalizeAttributeValue, variableNameRegex, wrapWith } from '../utils';
import { endOfLine, newLine, normalizeAttributeValue, variableNameRegex, wrapWith } from '../utils';
import { generateCamelized } from '../utils/camelized';
import type { TemplateCodegenContext } from './context';
import { generateElementChildren } from './elementChildren';
Expand All @@ -12,10 +12,9 @@ import { generateElementEvents } from './elementEvents';
import { type FailedPropExpression, generateElementProps } from './elementProps';
import type { TemplateCodegenOptions } from './index';
import { generateInterpolation } from './interpolation';
import { generateObjectProperty } from './objectProperty';
import { generatePropertyAccess } from './propertyAccess';
import { collectStyleScopedClassReferences } from './styleScopedClasses';
import { generateTemplateChild } from './templateChild';
import { generateVSlot } from './vSlot';

const colonReg = /:/g;

Expand Down Expand Up @@ -43,7 +42,6 @@ export function* generateComponent(
const isComponentTag = node.tag.toLowerCase() === 'component';

ctx.currentComponent = {
node,
ctxVar: var_defineComponentCtx,
used: false
};
Expand Down Expand Up @@ -151,6 +149,14 @@ export function* generateComponent(
}
else if (!isComponentTag) {
yield `const ${var_originalComponent} = ({} as __VLS_WithComponent<'${getCanonicalComponentName(node.tag)}', __VLS_LocalComponents, `;
if (options.selfComponentName && possibleOriginalNames.includes(options.selfComponentName)) {
yield `typeof __VLS_self & (new () => { `
+ getSlotsPropertyName(options.vueCompilerOptions.target)
+ `: typeof ${options.slotsAssignName ?? `__VLS_slots`} }), `;
}
else {
yield `void, `;
}
yield getPossibleOriginalComponentNames(node.tag, false)
.map(name => `'${name}'`)
.join(`, `);
Expand Down Expand Up @@ -269,24 +275,18 @@ export function* generateComponent(
yield `let ${var_componentEvents}!: __VLS_NormalizeEmits<typeof ${var_componentEmit}>${endOfLine}`;
}

if (
options.vueCompilerOptions.fallthroughAttributes
&& (
node.props.some(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE && prop.name === 'bind' && prop.exp?.loc.source === '$attrs')
|| node === ctx.singleRootNode
)
) {
const varAttrs = ctx.getInternalVariable();
ctx.inheritedAttrVars.add(varAttrs);
yield `var ${varAttrs}!: Parameters<typeof ${var_functionalComponent}>[0];\n`;
if (hasVBindAttrs(options, ctx, node)) {
const attrsVar = ctx.getInternalVariable();
ctx.inheritedAttrVars.add(attrsVar);
yield `let ${attrsVar}!: Parameters<typeof ${var_functionalComponent}>[0];\n`;
}

const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode;
if (slotDir) {
yield* generateComponentSlot(options, ctx, node, slotDir);
yield* generateVSlot(options, ctx, node, slotDir);
}
else {
yield* generateElementChildren(options, ctx, node);
yield* generateElementChildren(options, ctx, node, true);
}

if (ctx.currentComponent.used) {
Expand All @@ -306,7 +306,7 @@ export function* generateElement(
: undefined;
const failedPropExps: FailedPropExpression[] = [];

yield `__VLS_elementAsFunction(__VLS_intrinsicElements`;
yield `__VLS_asFunctionalElement(__VLS_intrinsicElements`;
yield* generatePropertyAccess(
options,
ctx,
Expand Down Expand Up @@ -349,23 +349,11 @@ export function* generateElement(
ctx.singleRootElType = `typeof __VLS_nativeElements['${node.tag}']`;
}

const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode;
if (slotDir && ctx.currentComponent) {
yield* generateComponentSlot(options, ctx, node, slotDir);
}
else {
yield* generateElementChildren(options, ctx, node);
}

if (
options.vueCompilerOptions.fallthroughAttributes
&& (
node.props.some(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE && prop.name === 'bind' && prop.exp?.loc.source === '$attrs')
|| node === ctx.singleRootNode
)
) {
if (hasVBindAttrs(options, ctx, node)) {
ctx.inheritedAttrVars.add(`__VLS_intrinsicElements.${node.tag}`);
}

yield* generateElementChildren(options, ctx, node);
}

function* generateFailedPropExps(
Expand Down Expand Up @@ -483,105 +471,6 @@ function* generateComponentGeneric(
ctx.lastGenericComment = undefined;
}

function* generateComponentSlot(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
node: CompilerDOM.ElementNode,
slotDir: CompilerDOM.DirectiveNode
): Generator<Code> {
yield `{${newLine}`;
if (ctx.currentComponent) {
ctx.currentComponent.used = true;
ctx.hasSlotElements.add(ctx.currentComponent.node);
}
const slotBlockVars: string[] = [];
yield `const {`;
if (slotDir?.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && slotDir.arg.content) {
yield* generateObjectProperty(
options,
ctx,
slotDir.arg.loc.source,
slotDir.arg.loc.start.offset,
slotDir.arg.isStatic ? ctx.codeFeatures.withoutHighlight : ctx.codeFeatures.all,
slotDir.arg.loc,
false,
true
);
}
else {
yield* wrapWith(
slotDir.loc.start.offset,
slotDir.loc.start.offset + (slotDir.rawName?.length ?? 0),
ctx.codeFeatures.withoutHighlightAndCompletion,
`default`
);
}
yield `: __VLS_thisSlot } = ${ctx.currentComponent!.ctxVar}.slots!${endOfLine}`;

if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const slotAst = createTsAst(options.ts, slotDir, `(${slotDir.exp.content}) => {}`);
collectVars(options.ts, slotAst, slotAst, slotBlockVars);
if (!slotDir.exp.content.includes(':')) {
yield `const [`;
yield [
slotDir.exp.content,
'template',
slotDir.exp.loc.start.offset,
ctx.codeFeatures.all,
];
yield `] = __VLS_getSlotParams(__VLS_thisSlot)${endOfLine}`;
}
else {
yield `const `;
yield [
slotDir.exp.content,
'template',
slotDir.exp.loc.start.offset,
ctx.codeFeatures.all,
];
yield ` = __VLS_getSlotParam(__VLS_thisSlot)${endOfLine}`;
}
}

for (const varName of slotBlockVars) {
ctx.addLocalVariable(varName);
}

yield* ctx.resetDirectiveComments('end of slot children start');

let prev: CompilerDOM.TemplateChildNode | undefined;
for (const childNode of node.children) {
yield* generateTemplateChild(options, ctx, childNode, prev);
prev = childNode;
}

for (const varName of slotBlockVars) {
ctx.removeLocalVariable(varName);
}
let isStatic = true;
if (slotDir?.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
isStatic = slotDir.arg.isStatic;
}
if (isStatic && slotDir && !slotDir.arg) {
yield `${ctx.currentComponent!.ctxVar}.slots!['`;
yield [
'',
'template',
slotDir.loc.start.offset + (
slotDir.loc.source.startsWith('#')
? '#'.length : slotDir.loc.source.startsWith('v-slot:')
? 'v-slot:'.length
: 0
),
ctx.codeFeatures.completion,
];
yield `'/* empty slot name completion */]${newLine}`;
}

yield* ctx.generateAutoImportCompletion();
yield `}${newLine}`;
}

function* generateReferencesForElements(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
Expand Down Expand Up @@ -617,6 +506,21 @@ function* generateReferencesForElements(
return [];
}

function hasVBindAttrs(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
node: CompilerDOM.ElementNode
) {
return options.vueCompilerOptions.fallthroughAttributes && (
node === ctx.singleRootNode ||
node.props.some(prop =>
prop.type === CompilerDOM.NodeTypes.DIRECTIVE
&& prop.name === 'bind'
&& prop.exp?.loc.source === '$attrs'
)
);
}

function camelizeComponentName(newName: string) {
return camelize('-' + newName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { generateTemplateChild } from './templateChild';
export function* generateElementChildren(
options: TemplateCodegenOptions,
ctx: TemplateCodegenContext,
node: CompilerDOM.ElementNode
node: CompilerDOM.ElementNode,
isDefaultSlot: boolean = false
): Generator<Code> {
yield* ctx.resetDirectiveComments('end of element children start');
let prev: CompilerDOM.TemplateChildNode | undefined;
Expand All @@ -21,10 +22,9 @@ export function* generateElementChildren(
// fix https://github.com/vuejs/language-tools/issues/932
if (
ctx.currentComponent
&& !ctx.hasSlotElements.has(node)
&& isDefaultSlot
&& node.children.length
&& node.tagType !== CompilerDOM.ElementTypes.ELEMENT
&& node.tagType !== CompilerDOM.ElementTypes.TEMPLATE
&& node.tagType === CompilerDOM.ElementTypes.COMPONENT
) {
ctx.currentComponent.used = true;
yield `${ctx.currentComponent.ctxVar}.slots!.`;
Expand Down
Loading

0 comments on commit 4fcbfa4

Please sign in to comment.