Commit 80d3f8df authored by Wiktor Walasek's avatar Wiktor Walasek

Complex inner types implementation

parent 6ab568a6
......@@ -46,6 +46,54 @@ const vertiacallyAlignableTags = [
'yields',
]
const typePrefixMap = {
'NullableType': '?',
'NonNullableType': '!',
}
/**
* Return properly formatted tag type name. Call itself recursively for complex
* inner types
*
* @param {Object} tagType Tag type object from parsed jsdoc
* @param {Boolean} unionTypeParentheses flag for parentheses around union type
* @returns {String} Formatted tag type
*/
function getTagTypeName(tagType, unionTypeParentheses) {
let { name } = tagType
if (name) return name
let { type, expression, applications, elements, prefix } = tagType
switch (type) {
case 'UndefinedLiteral':
return 'undefined'
case 'NullLiteral':
return 'null'
case 'AllLiteral':
return '*'
case 'RestType':
return `...${getTagTypeName(expression)}`
case 'NullableType':
case 'NonNullableType':
return `${prefix ? typePrefixMap[type] : ''}${getTagTypeName(expression)}`
case 'TypeApplication':
return `${getTagTypeName(expression)}.<${applications.map(a => getTagTypeName(a)).join(', ')}>`
case 'OptionalType':
return getTagTypeName(expression)
case 'UnionType':
return `${
unionTypeParentheses ? '(' : ''
}${elements.map(e => getTagTypeName(e)).join('|')}${
unionTypeParentheses ? ')' : ''
}`
default:
return ''
}
}
/**
* Trim, make single line with capitalized text. Insert dot if flag for it is
* set to true and last character is a word character
......@@ -114,35 +162,7 @@ function jsdocParser(text, parsers, options) {
if (tag.type) {
// Figure out tag.type.name
if (!tag.type.name) {
const typeNameMap = {
'UndefinedLiteral': 'undefined',
'NullLiteral': 'null',
}
if (Object.keys(typeNameMap).includes(tag.type.type)) {
tag.type.name = typeNameMap[tag.type.type]
}
if (tag.type.expression) {
tag.type.name = tag.type.expression.name
tag.type.elements = tag.type.expression.elements
if (tag.type.applications) {
let { type: { applications: [{ type, name, elements }] }} = tag
tag.type.name += '.<'
if (name) tag.type.name += Object.keys(typeNameMap).includes(type) ? typeNameMap[type] : name
if (elements) tag.type.name += elements
.map(({ type: t, name: n }) => Object.keys(typeNameMap).includes(t) ? typeNameMap[t] : n)
.join('|')
tag.type.name += '>'
}
}
if (tag.type.elements) {
tag.type.name = tag.type.elements.map(e => {
return typeNameMap[e.type] || e.name || 'undefined'
}).join('|')
}
}
tag.type.name = getTagTypeName(tag.type, options.jsdocUnionTypeParentheses)
if (vertiacallyAlignableTags.includes(tag.title))
maxTagTypeNameLength = Math.max(maxTagTypeNameLength, tag.type.name.length)
......@@ -312,6 +332,12 @@ module.exports = {
category: 'jsdoc',
default: false,
description: 'Should tags, types, names and description be aligned',
},
jsdocUnionTypeParentheses: {
type: 'boolean',
category: 'jsdoc',
default: false,
description: 'Should union type be enclosed in parentheses'
}
},
defaultOptions: {
......@@ -320,5 +346,6 @@ module.exports = {
jsdocDescriptionWithDot: false,
jsdocDescriptionTag: true,
jsdocVerticalAlignment: false,
jsdocUnionTypeParentheses: false,
}
}
......@@ -1564,8 +1564,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
......@@ -1586,14 +1585,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
......@@ -1608,20 +1605,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
......@@ -1738,8 +1732,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
......@@ -1751,7 +1744,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
......@@ -1766,7 +1758,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
......@@ -1774,14 +1765,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
......@@ -1800,7 +1789,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
......@@ -1881,8 +1869,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
......@@ -1894,7 +1881,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
......@@ -1980,8 +1966,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
......@@ -2017,7 +2002,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
......@@ -2037,7 +2021,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
......@@ -2081,14 +2064,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
......
......@@ -206,6 +206,51 @@ test('Should keep defined inner types', () => {
expect(Result5).toEqual(Expected5)
})
test('Sould keep complex inner types', () => {
const Result1 = subject(`/**
* @param {(String|Number)[]} test test param
* @param {Object.<String, Number>[]} test test param
* @param {...Number} test Test param
* @param {?Number} test Test param
* @param {?undefined} test Test param
* @param {!Number} test Test param
* @param {Number} test Test param
* @param {Number|String} test Test param
* @param {undefined} test Test param
* @param {*} test Test param
*/`)
const Expected1 = `/**
* @param {Array.<String|Number>} test Test param
* @param {Array.<Object.<String, Number>>} test Test param
* @param {...Number} test Test param
* @param {?Number} test Test param
* @param {?undefined} test Test param
* @param {!Number} test Test param
* @param {Number} test Test param
* @param {Number|String} test Test param
* @param {undefined} test Test param
* @param {*} test Test param
*/
`
expect(Result1).toEqual(Expected1)
})
test('Should add parentheses to union type if option set to true', () => {
const options = {
jsdocUnionTypeParentheses: true,
}
const Result1 = subject(`/**
* @param {Number|String} test Test param
*/`, options)
const Expected1 = `/**
* @param {(Number|String)} test Test param
*/
`
expect(Result1).toEqual(Expected1)
})
test('Should align vertically param|property|return|yields|throws if option set to true', () => {
const options = {
jsdocVerticalAlignment: true
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment