@enterthenamehere/esdoc
Version:
Good Documentation Generator For JavaScript, updated for new decade
170 lines (152 loc) • 5.28 kB
JavaScript
/**
* Param Type Parser class.
*/
export default class ParamParser {
/**
* parse param value.
* @param {string} value - param value.
* @param {boolean} [type=true] if true, contain param type.
* @param {boolean} [name=true] if true, contain param name.
* @param {boolean} [desc=true] if true, contain param description.
* @return {{typeText: string, paramName: string, paramDesc: string}} parsed value.
*
* @example
* let value = '{number} param - this is number param';
* let {typeText, paramName, paramDesc} = ParamParser.parseParamValue(value);
*
* let value = '{number} this is number return value';
* let {typeText, paramDesc} = ParamParser.parseParamValue(value, true, false, true);
*
* let value = '{number}';
* let {typeText} = ParamParser.parseParamValue(value, true, false, false);
*/
static parseParamValue(value, type = true, name = true, desc = true) {
value = value.trim();
let match = [];
let typeText = null;
let paramName = null;
let paramDesc = null;
// e.g {number}
if (type) {
const reg = /^\{([^@]*?)\}(\s+|$)/u; // ``@`` is special char in ``{@link foo}``
match = value.match(reg);
if (match) {
typeText = match[1];
value = value.replace(reg, '');
} else {
typeText = '*';
}
}
// e.g. [p1=123]
if (name) {
if (value.charAt(0) === '[') {
paramName = '';
let counter = 0;
for (const c of value) {
paramName += c;
if (c === '[') counter++;
if (c === ']') counter--;
if (counter === 0) break;
}
if (paramName) {
value = value.substr(paramName.length).trim();
}
} else {
match = value.match(/^(\S+)/u);
if (match) {
paramName = match[1];
value = value.replace(/^\S+\s*/u, '');
}
}
}
// e.g. this is p1 desc.
if (desc) {
paramDesc = ( value.startsWith('-') ? value.substring(1).trimStart() : value );
}
if( !(typeText || paramName || paramDesc ) ) {
console.error(`[31mParamParser::parseParamValue() - Param is invalid. param = "${value}"[0m`);
throw new Error(`ParamParser::parseParamValue() - Param is invalid. param = "${value}"`);
}
return {typeText, paramName, paramDesc};
}
/**
* parse param text and build formatted result.
* @param {string} typeText - param type text.
* @param {string} [paramName] - param name.
* @param {string} [paramDesc] - param description.
* @returns {ParsedParam} formatted result.
*
* @example
* let value = '{number} param - this is number param';
* let {typeText, paramName, paramDesc} = ParamParser.parseParamValue(value);
* let result = ParamParser.parseParam(typeText, paramName, paramDesc);
*/
static parseParam(typeText = null, paramName = null, paramDesc = null) {
const result = {};
if (typeText) {
// check nullable
if (typeText[0] === '?') {
result.nullable = true;
} else if (typeText[0] === '!') {
result.nullable = false;
} else {
result.nullable = null;
}
typeText = typeText.replace(/^[?!]/u, '');
// check record and union
if (typeText[0] === '{') {
result.types = [typeText];
} else if (typeText[0] === '(') {
typeText = typeText.replace(/^[(]/u, '').replace(/[)]$/u, '');
result.types = typeText.split('|');
} else if (typeText.includes('|')) {
if (typeText.match(/<.*?\|.*?>/u)) {
// union in generics. e.g. `Array<string|number>`
// hack: in this case, process this type in DocBuilder#_buildTypeDocLinkHTML
result.types = [typeText];
} else if (typeText.match(/^\.\.\.\(.*?\)/u)) {
// union with spread. e.g. `...(string|number)`
// hack: in this case, process this type in DocBuilder#_buildTypeDocLinkHTML
result.types = [typeText];
} else {
result.types = typeText.split('|');
}
} else {
result.types = [typeText];
}
if (typeText.indexOf('...') === 0) {
result.spread = true;
} else {
result.spread = false;
}
} else {
result.types = [''];
}
if (result.types.some((t) => { return !t; })) {
throw new Error(`Empty Type found name=${paramName} desc=${paramDesc}`);
}
if (paramName) {
// check optional
if (paramName[0] === '[') {
result.optional = true;
paramName = paramName.replace(/^[[]/u, '').replace(/[\]]$/u, '');
} else {
result.optional = false;
}
// check default value
const pair = paramName.split('=');
if (pair.length === 2) {
result.defaultValue = pair[1];
try {
const raw = JSON.parse(pair[1]);
result.defaultRaw = raw;
} catch (e) {
result.defaultRaw = pair[1];
}
}
result.name = pair[0].trim();
}
result.description = paramDesc;
return result;
}
}