Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix PropSync and Model decorators for vue property decorator #2164

Merged
merged 4 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
41 changes: 26 additions & 15 deletions server/src/modes/script/componentInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,24 @@ function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: t
return undefined;
}

return propsSymbols.map(prop => {
return propsSymbols.map(propSymbol => {
const prop = propSymbol.valueDeclaration as ts.PropertyDeclaration;
const decoratorExpr = prop.decorators?.find(decorator =>
tsModule.isCallExpression(decorator.expression)
? propDecoratorNames.includes(decorator.expression.expression.getText())
: false
)?.expression as ts.CallExpression;
const decoratorName = decoratorExpr.expression.getText();
const args = decoratorExpr.arguments;

const firstNode = args[0];
octref marked this conversation as resolved.
Show resolved Hide resolved
if (decoratorName === 'PropSync' && tsModule.isStringLiteral(firstNode)) {
return { name: firstNode.text, documentation: buildDocumentation(tsModule, propSymbol, checker) };
}

return {
name: prop.name,
documentation: buildDocumentation(tsModule, prop, checker)
name: propSymbol.name,
documentation: buildDocumentation(tsModule, propSymbol, checker)
};
});
}
Expand Down Expand Up @@ -412,12 +426,16 @@ export function getClassDecoratorArgumentType(
defaultExportNode: ts.Type,
checker: ts.TypeChecker
) {
const decorators = defaultExportNode.symbol.declarations[0].decorators;
const decorators = defaultExportNode.symbol.valueDeclaration.decorators;
if (!decorators || decorators.length === 0) {
return undefined;
}

const decoratorArguments = (decorators[0].expression as ts.CallExpression).arguments;
if (!tsModule.isCallExpression(decorators?.[0].expression)) {
return undefined;
}

const decoratorArguments = decorators?.[0].expression?.arguments;
if (!decoratorArguments || decoratorArguments.length === 0) {
return undefined;
}
Expand Down Expand Up @@ -450,11 +468,7 @@ function getPropertyDecoratorNames(property: ts.Symbol, checkSyntaxKind: ts.Synt
return [];
}

if (property.declarations.length === 0) {
return [];
}

const decorators = property.declarations[0].decorators;
const decorators = property?.valueDeclaration?.decorators;
if (decorators === undefined) {
return [];
}
Expand All @@ -474,12 +488,9 @@ export function buildDocumentation(tsModule: T_TypeScript, s: ts.Symbol, checker
documentation += '\n';

if (s.valueDeclaration) {
if (s.valueDeclaration.kind === tsModule.SyntaxKind.PropertyAssignment) {
documentation += `\`\`\`js\n${formatJSLikeDocumentation(s.valueDeclaration.getText())}\n\`\`\`\n`;
} else {
documentation += `\`\`\`js\n${formatJSLikeDocumentation(s.valueDeclaration.getText())}\n\`\`\`\n`;
}
documentation += `\`\`\`js\n${formatJSLikeDocumentation(s.valueDeclaration.getText())}\n\`\`\`\n`;
}

return documentation;
}

Expand Down
49 changes: 29 additions & 20 deletions test/interpolation/features/completion/property.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,39 @@ describe('Should autocomplete interpolation for <template> in property class com
]);
});

const propsList = [
{
label: ':foo',
kind: CompletionItemKind.Value,
documentation: new MarkdownString('My foo').appendCodeblock(
`@Prop({ type: Boolean, default: false }) foo`,
'js'
)
},
{
label: ':bar',
kind: CompletionItemKind.Value,
documentation: new MarkdownString('My bar').appendCodeblock(
`@PropSync('bar', { type: String }) syncedBar`,
'js'
)
},
{
label: ':checked',
kind: CompletionItemKind.Value,
documentation: new MarkdownString('My checked').appendCodeblock(
`@Model('change', { type: Boolean }) checked`,
'js'
)
}
];

it(`completes child component's props`, async () => {
await testCompletion(parentTemplateDocUri, position(2, 27), [
{
label: ':foo',
kind: CompletionItemKind.Value,
documentation: new MarkdownString('My foo').appendCodeblock(
`@Prop({ type: Boolean, default: false }) foo`,
'js'
)
}
]);
await testCompletion(parentTemplateDocUri, position(2, 27), propsList);
});

it(`completes child component's props when camel case component name`, async () => {
await testCompletion(parentTemplateDocUri, position(4, 24), [
{
label: ':foo',
kind: CompletionItemKind.Value,
documentation: new MarkdownString('My foo').appendCodeblock(
`@Prop({ type: Boolean, default: false }) foo`,
'js'
)
}
]);
await testCompletion(parentTemplateDocUri, position(4, 24), propsList);
});

it('completes inside v-if=""', async () => {
Expand Down
10 changes: 10 additions & 0 deletions test/interpolation/fixture/completion/propertyDecorator/Child.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ export default class BasicPropertyClass extends Vue {
*/
@Prop({ type: Boolean, default: false }) foo

/**
* My bar
*/
@PropSync('bar', { type: String }) syncedBar

/**
* My checked
*/
@Model('change', { type: Boolean }) checked

/**
* My msg
*/
Expand Down