Skip to content

Commit

Permalink
Handle v-model when prop validator
Browse files Browse the repository at this point in the history
  • Loading branch information
yoyo930021 authored and octref committed Sep 4, 2020
1 parent 2ece375 commit c652d6d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
38 changes: 37 additions & 1 deletion server/src/modes/script/componentInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,41 @@ export function getDefaultExportNode(tsModule: T_TypeScript, sourceFile: ts.Sour
}

function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: ts.TypeChecker): PropInfo[] | undefined {
const result: PropInfo[] = getClassAndObjectInfo(tsModule, defaultExportType, checker, getClassProps, getObjectProps);
const result: PropInfo[] = setDefaultModelForProps(
defaultExportType,
getClassAndObjectInfo(tsModule, defaultExportType, checker, getClassProps, getObjectProps)
);

return result.length === 0 ? undefined : result;

function setDefaultModelForProps (type: ts.Type, props: PropInfo[]) {
function setValuePropToDefaultModel () {
return props.map((prop) => {
if (prop.name === 'value') { prop.defaultModel = true; }
return prop;
});
}

const modelSymbol = checker.getPropertyOfType(type, 'model');
const modelValue = (modelSymbol?.valueDeclaration as ts.PropertyAssignment)?.initializer;
// Set value prop when no model def
if (!modelSymbol || !modelValue) {
return setValuePropToDefaultModel();
}

const modelType = checker.getTypeOfSymbolAtLocation(modelSymbol, modelValue);
const modelPropSymbol = checker.getPropertyOfType(modelType, 'prop');
const modelPropValue = (modelPropSymbol?.valueDeclaration as ts.PropertyAssignment)?.initializer;
if (!modelPropValue || !tsModule.isStringLiteral(modelPropValue)) {
return setValuePropToDefaultModel();
}

return props.map((prop) => {
if (prop.name === modelPropValue.text) { prop.defaultModel = true; }
return prop;
});
}

function getPropValidatorInfo(
propertyValue: ts.Node | undefined
): { hasObjectValidator: boolean; required: boolean } {
Expand Down Expand Up @@ -149,13 +181,15 @@ function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: t
return {
name: firstNode.text,
...getPropValidatorInfo(secondNode),
defaultModel: false,
documentation: buildDocumentation(tsModule, propSymbol, checker)
};
}

return {
name: propSymbol.name,
...getPropValidatorInfo(decoratorName === 'Model' ? secondNode : firstNode),
defaultModel: decoratorName === 'Model',
documentation: buildDocumentation(tsModule, propSymbol, checker)
};
});
Expand Down Expand Up @@ -183,6 +217,7 @@ function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: t
name: (expr as ts.StringLiteral).text,
hasObjectValidator: false,
required: true,
defaultModel: false,
documentation: `\`\`\`js\n${formatJSLikeDocumentation(
propsDeclaration.parent.getFullText().trim()
)}\n\`\`\`\n`
Expand Down Expand Up @@ -213,6 +248,7 @@ function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: t
return {
name: s.name,
...status,
defaultModel: false,
documentation: buildDocumentation(tsModule, s, checker)
};
});
Expand Down
19 changes: 16 additions & 3 deletions server/src/modes/template/services/vuePropValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ function generateDiagnostic(n: Node, definedProps: PropInfo[], document: TextDoc
const seenProps = n.attributeNames.map(attr => {
return {
name: attr,
normalized: normalizeHtmlAttributeNameToKebabCase(attr)
normalized: normalizeHtmlAttributeNameToKebabCase(
attr,
definedProps.find(prop => prop.defaultModel)?.name ?? 'value'
)
};
});

Expand Down Expand Up @@ -82,16 +85,26 @@ function generateDiagnostic(n: Node, definedProps: PropInfo[], document: TextDoc
};
}

function normalizeHtmlAttributeNameToKebabCase(attr: string) {
function normalizeHtmlAttributeNameToKebabCase(attr: string, defaultModel: string) {
let result = attr;

// v-model.trim
if (!result.startsWith('v-model:') && result.startsWith('v-model')) {
return kebabCase(defaultModel);
}

// Allow `v-model:prop` in vue 3
if (result.startsWith('v-model:')) {
result = attr.slice('v-model:'.length);
}

if (result.startsWith('v-bind:')) {
result = attr.slice('v-bind:'.length);
} else if (result.startsWith(':')) {
result = attr.slice(':'.length);
}

// Remove prop modifiers
// Remove modifiers
if (result.includes('.')) {
result = result.slice(0, result.indexOf('.'));
}
Expand Down
1 change: 1 addition & 0 deletions server/src/services/vueInfoService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export interface PropInfo {
*/
hasObjectValidator: boolean;
required: boolean;
defaultModel: boolean;
documentation?: string;
}
export interface DataInfo {
Expand Down

0 comments on commit c652d6d

Please sign in to comment.