Skip to content

Commit c4a295b

Browse files
authored
Fix: Primitive type inferred based on parameter default value (#149)
* Fix: Primitive type inferred based on parameter default value * Fix default: in param
1 parent d52b52e commit c4a295b

File tree

5 files changed

+93
-59
lines changed

5 files changed

+93
-59
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@webdoc/parser",
5+
"comment": "Fix parameter type annotation parsing when parameter is assigned a default value (https://github.com/webdoc-labs/webdoc/issues/144)",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@webdoc/parser",
10+
"email": "[email protected]"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@webdoc/parser",
5+
"comment": "Add primitive type inference for untyped parameters with a default value (https://github.com/webdoc-labs/webdoc/issues/138)",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@webdoc/parser",
10+
"email": "[email protected]"
11+
}

packages/webdoc-parser/src/symbols-babel/extract-metadata.js

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// This file has helper functions for extracting metadata from AST nodes.
44

55
import {
6+
type BabelNodeExpression,
67
type BabelNodeFlow,
78
type BabelNodeMemberExpression,
89
type BabelNodeQualifiedName,
@@ -24,23 +25,27 @@ import {
2425
isAnyTypeAnnotation,
2526
isArrayTypeAnnotation,
2627
isAssignmentPattern,
28+
isBooleanLiteral,
2729
isBooleanLiteralTypeAnnotation,
2830
isBooleanTypeAnnotation,
2931
isClassDeclaration,
3032
isClassExpression,
3133
isClassImplements,
34+
isExpression,
3235
isFlowType,
3336
isFunctionTypeAnnotation,
3437
isFunctionTypeParam,
3538
isGenericTypeAnnotation,
3639
isIdentifier,
3740
isIntersectionTypeAnnotation,
41+
isLiteral,
3842
isMemberExpression,
3943
isMixedTypeAnnotation,
4044
isNullLiteralTypeAnnotation,
4145
isNullableTypeAnnotation,
4246
isNumberLiteralTypeAnnotation,
4347
isNumberTypeAnnotation,
48+
isNumericLiteral,
4449
isObjectExpression,
4550
isObjectTypeAnnotation,
4651
isObjectTypeIndexer,
@@ -95,6 +100,7 @@ import {
95100
isTypeAnnotation,
96101
isTypeParameterInstantiation,
97102
isTypeofTypeAnnotation,
103+
isUnaryExpression,
98104
isUnionTypeAnnotation,
99105
isVoidTypeAnnotation,
100106
} from "@babel/types";
@@ -217,13 +223,17 @@ export function extractParams(
217223
};
218224
} else if (isAssignmentPattern(paramNode)) {
219225
const extraRaw = paramNode.right.extra && paramNode.right.extra.raw;
226+
const [defaultValue, dataType] = extractAssignedValue(paramNode.right);
220227

221-
paramTypeAnnotation = paramNode.left.typeAnnotation;
222228
param = {
223229
identifier: paramNode.left.name,
224230
optional: paramNode.optional || false,
225-
default: paramNode.right.raw || extraRaw,
231+
default: paramNode.right.raw || extraRaw || defaultValue,
232+
dataType,
226233
};
234+
235+
// This will override the inferred data type.
236+
paramTypeAnnotation = paramNode.left.typeAnnotation;
227237
} else if (isObjectExpression(paramNode)) {
228238
// TODO: Find a way to document {x, y, z} parameters
229239
// e.g. function ({x, y, z}), you would need to give the object pattern an anonymous like
@@ -264,6 +274,53 @@ export function extractReturns(
264274
return [];
265275
}
266276

277+
// Used to get default value
278+
// TODO: Resolve a lot more expressions
279+
export function extractRawExpression(expression: BabelNodeExpression): string | void {
280+
if (isLiteral(expression)) {
281+
if (isStringLiteral(expression)) {
282+
return `"${expression.value}"`;
283+
} else {
284+
return `${expression.value}`;
285+
}
286+
}
287+
if (isUnaryExpression(expression)) {
288+
return `-${extractRawExpression(expression.argument) || ""}`;
289+
}
290+
}
291+
292+
export function extractAssignedValue(node: BabelNodeExpression): [?string, ?DataType] {
293+
let defaultValue: ?string;
294+
let dataType: ?DataType;
295+
296+
if (isLiteral(node)) {
297+
if (isStringLiteral(node)) {
298+
// Quotes for strings
299+
defaultValue = `"${node.value}"`;
300+
301+
dataType = createSimpleKeywordType("string");
302+
} else {
303+
defaultValue = `${node.value}`;
304+
305+
if (isNumericLiteral(node)) {
306+
dataType = createSimpleKeywordType("number");
307+
} else if (isBooleanLiteral(node)) {
308+
dataType = createSimpleKeywordType("boolean");
309+
}
310+
}
311+
} else if (isExpression(node)) {
312+
defaultValue = extractRawExpression(node);
313+
314+
if (typeof defaultValue === "string") {
315+
if (!isNaN(parseFloat(defaultValue))) {
316+
dataType = createSimpleKeywordType("number");
317+
}
318+
}
319+
}
320+
321+
return [defaultValue, dataType];
322+
}
323+
267324
// Failsafe
268325
export function extractTypeFailsafe(
269326
node: BabelNodeTypeAnnotation | BabelNodeTSTypeAnnotation | any,

packages/webdoc-parser/src/symbols-babel/extract-symbol.js

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import {
77
type ArrowFunctionExpression,
8-
type BabelNodeExpression,
98
type FunctionExpression,
109
type MemberExpression,
1110
type Node,
@@ -14,26 +13,22 @@ import {
1413
isArrowFunctionExpression,
1514
isAssignmentExpression,
1615
isAssignmentPattern,
17-
isBooleanLiteral,
1816
isCallExpression,
1917
isClassDeclaration,
2018
isClassExpression,
2119
isClassMethod,
2220
isClassProperty,
23-
isExpression,
2421
isExpressionStatement,
2522
isFunctionDeclaration,
2623
isFunctionExpression,
2724
isIdentifier,
2825
isInterfaceDeclaration,
2926
isLiteral,
3027
isMemberExpression,
31-
isNumericLiteral,
3228
isObjectExpression,
3329
isObjectMethod,
3430
isObjectProperty,
3531
isReturnStatement,
36-
isStringLiteral,
3732
isTSAsExpression,
3833
isTSDeclareFunction,
3934
isTSDeclareMethod,
@@ -45,21 +40,19 @@ import {
4540
isTSPropertySignature,
4641
isTSTypeElement,
4742
isThisExpression,
48-
isUnaryExpression,
4943
isVariableDeclarator,
5044
} from "@babel/types";
5145

5246
import {OBLIGATE_LEAF, PASS_THROUGH, type Symbol, VIRTUAL, isVirtual} from "../types/Symbol";
5347
import {PARAMETER, queryType} from "../types/VariableRegistry";
5448
import {
49+
extractAssignedValue,
5550
extractExtends,
5651
extractImplements,
5752
extractParams,
5853
extractReturns,
5954
extractType,
6055
} from "./extract-metadata";
61-
import type {DataType} from "@webdoc/types";
62-
import {createSimpleKeywordType} from "@webdoc/model";
6356

6457
// + Extract the symbol name, type from the Node
6558
// + Set the appopriate flags
@@ -121,7 +114,7 @@ export default function extractSymbol(
121114
nodeSymbol.meta.scope = node.static ? "static" : "instance";
122115
nodeSymbol.meta.type = "PropertyDoc";
123116

124-
const [defaultValue, dataType] = resolveDefaultValue(node.value);
117+
const [defaultValue, dataType] = extractAssignedValue(node.value);
125118

126119
if (typeof defaultValue === "string") {
127120
nodeSymbol.meta.defaultValue = defaultValue;
@@ -243,7 +236,7 @@ export default function extractSymbol(
243236

244237
// Resolve property default
245238
if (!isInit && init) {
246-
const [defaultValue, dataType] = resolveDefaultValue(init);
239+
const [defaultValue, dataType] = extractAssignedValue(init);
247240

248241
nodeSymbol.meta.defaultValue = defaultValue;
249242
nodeSymbol.meta.dataType = dataType;
@@ -429,53 +422,6 @@ function resolveRootObject(expression: MemberExpression): string {
429422
return isThisExpression(expression) ? "this" : expression.name;
430423
}
431424

432-
// Used to get default value
433-
// TODO: Resolve a lot more expressions
434-
function resolveExpression(expression: BabelNodeExpression): string | void {
435-
if (isLiteral(expression)) {
436-
if (isStringLiteral(expression)) {
437-
return `"${expression.value}"`;
438-
} else {
439-
return `${expression.value}`;
440-
}
441-
}
442-
if (isUnaryExpression(expression)) {
443-
return `-${resolveExpression(expression.argument) || ""}`;
444-
}
445-
}
446-
447-
function resolveDefaultValue(node: BabelNodeExpression): [?string, ?DataType] {
448-
let defaultValue: ?string;
449-
let dataType: ?DataType;
450-
451-
if (isLiteral(node)) {
452-
if (isStringLiteral(node)) {
453-
// Quotes for strings
454-
defaultValue = `"${node.value}"`;
455-
456-
dataType = createSimpleKeywordType("string");
457-
} else {
458-
defaultValue = `${node.value}`;
459-
460-
if (isNumericLiteral(node)) {
461-
dataType = createSimpleKeywordType("number");
462-
} else if (isBooleanLiteral(node)) {
463-
dataType = createSimpleKeywordType("boolean");
464-
}
465-
}
466-
} else if (isExpression(node)) {
467-
defaultValue = resolveExpression(node);
468-
469-
if (typeof defaultValue === "string") {
470-
if (!isNaN(parseFloat(defaultValue))) {
471-
dataType = createSimpleKeywordType("number");
472-
}
473-
}
474-
}
475-
476-
return [defaultValue, dataType];
477-
}
478-
479425
// Whether the member expression assigns to this, e.g.
480426
// this.member.inside.deep -> true
481427
// top.inside -> false

packages/webdoc-parser/test/lang-ts.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,13 @@ describe("@webdoc/parser.LanguageIntegration{@lang ts}", function() {
203203

204204
expect(symbolTree.members[0].meta.params[0].dataType[0]).to.equal("object | string");
205205
});
206+
207+
it("should infer primitive parameter types", function() {
208+
const symbolTree = buildSymbolTree(`
209+
function mark(what = 'test') {
210+
}
211+
`);
212+
213+
expect(symbolTree.members[0].meta.params[0].dataType[0]).to.equal("string");
214+
});
206215
});

0 commit comments

Comments
 (0)