From f863a487025cb1b80262e232b868d79780700a6a Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rousseau Date: Sun, 29 Nov 2020 16:10:44 -0500 Subject: [PATCH 1/2] fix(v3-parser): Export metadata for method.param items (#39) - Add function getDefaultJSDocType - Update tests for svelte3/integration/methods - Fix typings for SvelteMethodItem - Add example usage --- examples/Button.json | 14 +++++-- examples/Button.svelte | 4 +- lib/jsdoc.js | 23 ++++++----- lib/v3/parser.js | 39 +++++++++++++++---- .../integration/methods/method.public.svelte | 2 + .../integration/methods/methods.spec.js | 30 +++++++++----- typings.d.ts | 7 +++- 7 files changed, 83 insertions(+), 36 deletions(-) diff --git a/examples/Button.json b/examples/Button.json index ff1fbc3..2306fd4 100644 --- a/examples/Button.json +++ b/examples/Button.json @@ -132,7 +132,7 @@ "keywords": [ { "name": "param", - "description": "{string} question a question about life, the universe, everything" + "description": "{string} [question=Why?] a question about life, the universe, everything" }, { "name": "returns", @@ -142,9 +142,17 @@ "visibility": "public", "description": "Computes the answer to your question.", "name": "computeAnswer", - "args": [ + "params": [ { - "name": "question" + "type": { + "kind": "type", + "text": "string", + "type": "string" + }, + "name": "question", + "optional": true, + "default": "Why?", + "description": "a question about life, the universe, everything" } ], "return": { diff --git a/examples/Button.svelte b/examples/Button.svelte index ac73cfe..fe0834c 100644 --- a/examples/Button.svelte +++ b/examples/Button.svelte @@ -33,11 +33,11 @@ /** * Computes the answer to your question. - * @param {string} question a question about life, the universe, everything + * @param {string} [question=Why?] a question about life, the universe, everything * @returns {number} the answer to all your questions */ export function computeAnswer(question) { - return question.indexOf("?") >= 0 ? 42 : 23; + return question.indexOf('?') >= 0 ? 42 : 23; }; diff --git a/lib/jsdoc.js b/lib/jsdoc.js index 6302e21..2329d4a 100644 --- a/lib/jsdoc.js +++ b/lib/jsdoc.js @@ -11,6 +11,14 @@ const RETURN_RE = new RegExp(`^\\s*(${TYPE})?(\\s*${TYPE_DESC})?`, 'i'); const DEFAULT_TYPE = 'any'; +function getDefaultJSDocType() { + return { + kind: 'type', + text: '*', + type: DEFAULT_TYPE + }; +} + function parseType(type, param) { if (type.indexOf('|') > -1) { param.type = type.split('|'); @@ -111,15 +119,10 @@ function parseTypeKeyword(text) { function parseParamKeyword(text) { const param = { - type: { - kind: 'type', - text: '*', - type: DEFAULT_TYPE - }, + type: getDefaultJSDocType(), name: null, optional: false, - default: null, - description: null + default: null }; const match = PARAM_RE.exec(text); @@ -169,11 +172,7 @@ function parseParamKeyword(text) { function parseReturnKeyword(text) { const output = { - type: { - kind: 'type', - text: '*', - type: DEFAULT_TYPE - }, + type: getDefaultJSDocType(), description: null }; const matches = RETURN_RE.exec(text); diff --git a/lib/v3/parser.js b/lib/v3/parser.js index 8ee6e79..d99e27d 100644 --- a/lib/v3/parser.js +++ b/lib/v3/parser.js @@ -150,7 +150,7 @@ class Parser extends EventEmitter { const item = Object.assign({}, comment, { name: method.name, - args: method.args, + params: method.params, return: method.return, static: parseContext.scopeType === SCOPE_STATIC }); @@ -679,11 +679,11 @@ class Parser extends EventEmitter { throw new Error('Node should have a FunctionDeclarationType, but is ' + node.type); } - const args = []; + const params = []; - node.params.forEach(param => { + node.params.forEach((param) => { if (param.type === 'Identifier') { - args.push({ + params.push({ name: param.name, }); } @@ -696,7 +696,7 @@ class Parser extends EventEmitter { start: node.id.start, end: node.id.end }, - args: args, + params: params, }; return output; @@ -916,15 +916,40 @@ class Parser extends EventEmitter { parser.end(); } + /** + * Mutates event. + * @param {any[]} keywords + * @param {{ params?: any[] }} event + */ parseKeywords(keywords = [], event) { - event.params = []; + if (!event.params) event.params = []; keywords.forEach(({ name, description }) => { switch (name) { case 'arg': case 'param': case 'argument': - event.params.push(jsdoc.parseParamKeyword(description)); + const parsedParam = jsdoc.parseParamKeyword(description); + const pIndex = event.params.findIndex( + p => p.name === parsedParam.name + ); + + /* + * Replace the param if there is already one present with + * the same name. This will happen with parsed + * FunctionDeclaration because params will already be + * present from parsing the AST node. + */ + if (0 <= pIndex) { + event.params[pIndex] = parsedParam; + } else { + /* + * This means @param does not match an actual param + * in the FunctionDeclaration. + * Should we ignore it or warn about it? + */ + event.params.push(parsedParam); + } break; case 'return': diff --git a/test/svelte3/integration/methods/method.public.svelte b/test/svelte3/integration/methods/method.public.svelte index f3a5bc4..ae1ddf7 100644 --- a/test/svelte3/integration/methods/method.public.svelte +++ b/test/svelte3/integration/methods/method.public.svelte @@ -1,6 +1,8 @@