Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/classname-docume…
Browse files Browse the repository at this point in the history
…nt-links
  • Loading branch information
KazariEX committed Aug 12, 2024
2 parents 1f3053c + 0f14cde commit cf96978
Show file tree
Hide file tree
Showing 56 changed files with 862 additions and 284 deletions.
5 changes: 5 additions & 0 deletions extensions/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,11 @@
"default": true,
"description": "Auto add space between double curly brackets: {{|}} -> {{ | }}"
},
"vue.inlayHints.destructuredProps": {
"type": "boolean",
"default": false,
"description": "Show inlay hints for destructured prop."
},
"vue.inlayHints.missingProps": {
"type": "boolean",
"default": false,
Expand Down
28 changes: 23 additions & 5 deletions packages/language-core/lib/codegen/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,45 @@ export function collectVars(
ts: typeof import('typescript'),
node: ts.Node,
ast: ts.SourceFile,
result: string[]
results: string[] = [],
includesRest = true
) {
const identifiers = collectIdentifiers(ts, node, [], includesRest);
for (const id of identifiers) {
results.push(getNodeText(ts, id, ast));
}
return results;
}

export function collectIdentifiers(
ts: typeof import('typescript'),
node: ts.Node,
results: ts.Identifier[] = [],
includesRest = true
) {
if (ts.isIdentifier(node)) {
result.push(getNodeText(ts, node, ast));
results.push(node);
}
else if (ts.isObjectBindingPattern(node)) {
for (const el of node.elements) {
collectVars(ts, el.name, ast, result);
if (includesRest || !el.dotDotDotToken) {
collectIdentifiers(ts, el.name, results, includesRest);
}
}
}
else if (ts.isArrayBindingPattern(node)) {
for (const el of node.elements) {
if (ts.isBindingElement(el)) {
collectVars(ts, el.name, ast, result);
collectIdentifiers(ts, el.name, results, includesRest);
}
}
}
else {
ts.forEachChild(node, node => collectVars(ts, node, ast, result));
ts.forEachChild(node, node => collectIdentifiers(ts, node, results, includesRest));
}
return results;
}

export function createTsAst(ts: typeof import('typescript'), astHolder: any, text: string) {
if (astHolder.__volar_ast_text !== text) {
astHolder.__volar_ast_text = text;
Expand Down
5 changes: 4 additions & 1 deletion packages/language-core/lib/codegen/script/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { getSlotsPropertyName } from '../../utils/shared';
import { newLine } from '../common';
import { InlayHintInfo } from '../types';
import type { ScriptCodegenOptions } from './index';

interface HelperType {
export interface HelperType {
name: string;
used?: boolean;
generated?: boolean;
Expand Down Expand Up @@ -102,6 +103,7 @@ export function createScriptCodegenContext(options: ScriptCodegenOptions) {
},
} satisfies HelperType as HelperType,
};
const inlayHints: InlayHintInfo[] = [];

return {
generatedTemplate: false,
Expand All @@ -113,6 +115,7 @@ export function createScriptCodegenContext(options: ScriptCodegenOptions) {
...options.scriptSetupRanges?.bindings.map(range => options.sfc.scriptSetup!.content.substring(range.start, range.end)) ?? [],
]),
helperTypes,
inlayHints,
generateHelperTypes,
};

Expand Down
1 change: 1 addition & 0 deletions packages/language-core/lib/codegen/script/globalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ declare global {
: false;
function __VLS_normalizeSlot<S>(s: S): S extends () => infer R ? (props: {}) => R : S;
function __VLS_tryAsConstant<const T>(t: T): T;
/**
* emit
Expand Down
56 changes: 23 additions & 33 deletions packages/language-core/lib/codegen/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges';
import type { Code, Sfc, VueCodeInformation, VueCompilerOptions } from '../../types';
import { endOfLine, generateSfcBlockSection, newLine } from '../common';
import type { TemplateCodegenContext } from '../template/context';
import { createScriptCodegenContext } from './context';
import { createScriptCodegenContext, ScriptCodegenContext } from './context';
import { generateGlobalTypes } from './globalTypes';
import { generateScriptSetup, generateScriptSetupImports } from './scriptSetup';
import { generateSrc } from './src';
Expand Down Expand Up @@ -49,7 +49,7 @@ export interface ScriptCodegenOptions {
linkedCodeMappings: Mapping[];
}

export function* generateScript(options: ScriptCodegenOptions): Generator<Code> {
export function* generateScript(options: ScriptCodegenOptions): Generator<Code, ScriptCodegenContext> {
const ctx = createScriptCodegenContext(options);

yield `/* __placeholder__ */${newLine}`;
Expand All @@ -74,40 +74,28 @@ export function* generateScript(options: ScriptCodegenOptions): Generator<Code>
}
}
else if (exportDefault && isExportRawObject && options.vueCompilerOptions.optionsWrapper.length) {
ctx.inlayHints.push({
blockName: options.sfc.script.name,
offset: exportDefault.expression.start,
setting: 'vue.inlayHints.optionsWrapper',
label: options.vueCompilerOptions.optionsWrapper.length
? options.vueCompilerOptions.optionsWrapper[0]
: '[Missing optionsWrapper[0]]',
tooltip: [
'This is virtual code that is automatically wrapped for type support, it does not affect your runtime behavior, you can customize it via `vueCompilerOptions.optionsWrapper` option in tsconfig / jsconfig.',
'To hide it, you can set `"vue.inlayHints.optionsWrapper": false` in IDE settings.',
].join('\n\n'),
}, {
blockName: options.sfc.script.name,
offset: exportDefault.expression.end,
setting: 'vue.inlayHints.optionsWrapper',
label: options.vueCompilerOptions.optionsWrapper.length >= 2
? options.vueCompilerOptions.optionsWrapper[1]
: '[Missing optionsWrapper[1]]',
});
yield generateSfcBlockSection(options.sfc.script, 0, exportDefault.expression.start, codeFeatures.all);
yield options.vueCompilerOptions.optionsWrapper[0];
yield [
'',
'script',
exportDefault.expression.start,
{
__hint: {
setting: 'vue.inlayHints.optionsWrapper',
label: options.vueCompilerOptions.optionsWrapper.length
? options.vueCompilerOptions.optionsWrapper[0]
: '[Missing optionsWrapper]',
tooltip: [
'This is virtual code that is automatically wrapped for type support, it does not affect your runtime behavior, you can customize it via `vueCompilerOptions.optionsWrapper` option in tsconfig / jsconfig.',
'To hide it, you can set `"vue.inlayHints.optionsWrapper": false` in IDE settings.',
].join('\n\n'),
}
},
];
yield generateSfcBlockSection(options.sfc.script, exportDefault.expression.start, exportDefault.expression.end, codeFeatures.all);
yield [
'',
'script',
exportDefault.expression.end,
{
__hint: {
setting: 'vue.inlayHints.optionsWrapper',
label: options.vueCompilerOptions.optionsWrapper.length === 2
? options.vueCompilerOptions.optionsWrapper[1]
: '[Missing optionsWrapper]',
tooltip: '',
}
},
];
yield options.vueCompilerOptions.optionsWrapper[1];
yield generateSfcBlockSection(options.sfc.script, exportDefault.expression.end, options.sfc.script.content.length, codeFeatures.all);
}
Expand Down Expand Up @@ -156,6 +144,8 @@ export function* generateScript(options: ScriptCodegenOptions): Generator<Code>
codeFeatures.verification,
];
}

return ctx;
}

function* generateDefineProp(
Expand Down
2 changes: 1 addition & 1 deletion packages/language-core/lib/codegen/script/scriptSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ function* generateDefinePropType(scriptSetup: NonNullable<Sfc['scriptSetup']>, p
}
else if ((defineProp.name && defineProp.nameIsString) || !defineProp.nameIsString) {
// Infer from actual prop declaration code
yield `NonNullable<typeof ${propName}['value']>`;
yield `typeof ${propName}['value']`;
}
else if (defineProp.defaultValue) {
// Infer from defineProp({default: T})
Expand Down
3 changes: 3 additions & 0 deletions packages/language-core/lib/codegen/template/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type * as CompilerDOM from '@vue/compiler-dom';
import type { Code, VueCodeInformation } from '../../types';
import { endOfLine, newLine, wrapWith } from '../common';
import type { TemplateCodegenOptions } from './index';
import { InlayHintInfo } from '../types';

const _codeFeatures = {
all: {
Expand Down Expand Up @@ -114,6 +115,7 @@ export function createTemplateCodegenContext(scriptSetupBindingNames: TemplateCo
offset: number;
}[] = [];
const emptyClassOffsets: number[] = [];
const inlayHints: InlayHintInfo[] = [];

return {
slots,
Expand All @@ -125,6 +127,7 @@ export function createTemplateCodegenContext(scriptSetupBindingNames: TemplateCo
usedComponentCtxVars,
scopedClasses,
emptyClassOffsets,
inlayHints,
hasSlot: false,
accessExternalVariable(name: string, offset?: number) {
let arr = accessExternalVariables.get(name);
Expand Down
32 changes: 25 additions & 7 deletions packages/language-core/lib/codegen/template/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function* generateComponent(
let props = node.props;
let dynamicTagInfo: {
exp: string;
offset: number;
offsets: [number, number | undefined];
astHolder: any;
} | undefined;

Expand All @@ -57,7 +57,7 @@ export function* generateComponent(
if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE && prop.name === 'bind' && prop.arg?.loc.source === 'is' && prop.exp) {
dynamicTagInfo = {
exp: prop.exp.loc.source,
offset: prop.exp.loc.start.offset,
offsets: [prop.exp.loc.start.offset, undefined],
astHolder: prop.exp.loc,
};
props = props.filter(p => p !== prop);
Expand All @@ -70,7 +70,7 @@ export function* generateComponent(
dynamicTagInfo = {
exp: node.tag,
astHolder: node.loc,
offset: startTagOffset,
offsets: [startTagOffset, endTagOffset],
};
}

Expand Down Expand Up @@ -105,18 +105,34 @@ export function* generateComponent(
yield `]${endOfLine}`;
}
else if (dynamicTagInfo) {
yield `const ${var_originalComponent} = `;
yield `const ${var_originalComponent} = (`;
yield* generateInterpolation(
options,
ctx,
dynamicTagInfo.exp,
dynamicTagInfo.astHolder,
dynamicTagInfo.offset,
dynamicTagInfo.offsets[0],
ctx.codeFeatures.all,
'(',
')'
);
yield endOfLine;
if (dynamicTagInfo.offsets[1] !== undefined) {
yield `,`;
yield* generateInterpolation(
options,
ctx,
dynamicTagInfo.exp,
dynamicTagInfo.astHolder,
dynamicTagInfo.offsets[1],
{
...ctx.codeFeatures.all,
completion: false,
},
'(',
')'
);
}
yield `)${endOfLine}`;
}
else if (!isComponentTag) {
yield `// @ts-ignore${newLine}`;
Expand Down Expand Up @@ -429,7 +445,9 @@ function* generateComponentSlot(
slotDir.arg.loc.source,
slotDir.arg.loc.start.offset,
slotDir.arg.isStatic ? ctx.codeFeatures.withoutHighlight : ctx.codeFeatures.all,
slotDir.arg.loc
slotDir.arg.loc,
false,
true
);
yield ': __VLS_thisSlot';
}
Expand Down
27 changes: 13 additions & 14 deletions packages/language-core/lib/codegen/template/elementEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,21 @@ export function* generateEventExpression(
prop.exp.content,
prop.exp.loc,
prop.exp.loc.start.offset,
() => {
offset => {
if (_isCompoundExpression && isFirstMapping) {
isFirstMapping = false;
return {
...ctx.codeFeatures.all,
__hint: {
setting: 'vue.inlayHints.inlineHandlerLeading',
label: '$event =>',
tooltip: [
'`$event` is a hidden parameter, you can use it in this callback.',
'To hide this hint, set `vue.inlayHints.inlineHandlerLeading` to `false` in IDE settings.',
'[More info](https://github.com/vuejs/language-tools/issues/2445#issuecomment-1444771420)',
].join('\n\n'),
paddingRight: true,
},
};
ctx.inlayHints.push({
blockName: 'template',
offset,
setting: 'vue.inlayHints.inlineHandlerLeading',
label: '$event =>',
paddingRight: true,
tooltip: [
'`$event` is a hidden parameter, you can use it in this callback.',
'To hide this hint, set `vue.inlayHints.inlineHandlerLeading` to `false` in IDE settings.',
'[More info](https://github.com/vuejs/language-tools/issues/2445#issuecomment-1444771420)',
].join('\n\n'),
});
}
return ctx.codeFeatures.all;
},
Expand Down
31 changes: 13 additions & 18 deletions packages/language-core/lib/codegen/template/elementProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ function* genereatePropExp(
exp: CompilerDOM.SimpleExpressionNode | undefined,
features: VueCodeInformation,
isShorthand: boolean,
inlayHints: boolean
enableCodeFeatures: boolean
): Generator<Code> {
if (exp && exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY) { // style='z-index: 2' will compile to {'z-index':'2'}
if (!isShorthand) { // vue 3.4+
Expand All @@ -296,23 +296,18 @@ function* genereatePropExp(
exp.loc.start.offset,
features
);
if (inlayHints) {
yield [
'',
'template',
exp.loc.end.offset,
{
__hint: {
setting: 'vue.inlayHints.vBindShorthand',
label: `="${propVariableName}"`,
tooltip: [
`This is a shorthand for \`${exp.loc.source}="${propVariableName}"\`.`,
'To hide this hint, set `vue.inlayHints.vBindShorthand` to `false` in IDE settings.',
'[More info](https://github.com/vuejs/core/pull/9451)',
].join('\n\n'),
},
} as VueCodeInformation,
];
if (enableCodeFeatures) {
ctx.inlayHints.push({
blockName: 'template',
offset: exp.loc.end.offset,
setting: 'vue.inlayHints.vBindShorthand',
label: `="${propVariableName}"`,
tooltip: [
`This is a shorthand for \`${exp.loc.source}="${propVariableName}"\`.`,
'To hide this hint, set `vue.inlayHints.vBindShorthand` to `false` in IDE settings.',
'[More info](https://github.com/vuejs/core/pull/9451)',
].join('\n\n'),
});
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/language-core/lib/codegen/template/interpolation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function* generateInterpolation(
_code: string,
astHolder: any,
start: number | undefined,
data: VueCodeInformation | (() => VueCodeInformation) | undefined,
data: VueCodeInformation | ((offset: number) => VueCodeInformation) | undefined,
prefix: string,
suffix: string
): Generator<Code> {
Expand Down Expand Up @@ -53,7 +53,7 @@ export function* generateInterpolation(
start + offset,
onlyError
? ctx.codeFeatures.verification
: typeof data === 'function' ? data() : data,
: typeof data === 'function' ? data(start + offset) : data,
];
}
else {
Expand Down
Loading

0 comments on commit cf96978

Please sign in to comment.