From 23514d87384e781cbf1cf19e4535428e50dcc4cf Mon Sep 17 00:00:00 2001 From: Alex Ivanov Date: Mon, 5 Aug 2019 14:21:21 +0300 Subject: [PATCH] Methods and imported data parsing --- lib/v3/parser.js | 87 ++++++++++++++++--- .../data/data.import.default.svelte | 8 ++ .../integration/data/data.import.many.svelte | 8 ++ test/svelte3/integration/data/data.spec.js | 56 ++++++++++++ test/svelte3/integration/data/importable.js | 3 + .../integration/methods/method.private.svelte | 8 ++ .../integration/methods/method.public.svelte | 8 ++ .../integration/methods/methods.spec.js | 62 +++++++++++++ typings.d.ts | 7 ++ 9 files changed, 233 insertions(+), 14 deletions(-) create mode 100644 test/svelte3/integration/data/data.import.default.svelte create mode 100644 test/svelte3/integration/data/data.import.many.svelte create mode 100644 test/svelte3/integration/data/importable.js create mode 100644 test/svelte3/integration/methods/method.private.svelte create mode 100644 test/svelte3/integration/methods/method.public.svelte create mode 100644 test/svelte3/integration/methods/methods.spec.js diff --git a/lib/v3/parser.js b/lib/v3/parser.js index 6c11036..4409474 100644 --- a/lib/v3/parser.js +++ b/lib/v3/parser.js @@ -11,16 +11,16 @@ const DEFAULT_OPTIONS = {}; const SUPPORTED_FEATURES = [ 'name', - 'data', - 'computed', - // 'methods', - // 'actions', - // 'helpers', - 'components', - // 'description', - 'events', - 'slots', - // 'transitions', + 'data', + 'computed', + 'methods', + // 'actions', + // 'helpers', + 'components', + // 'description', + 'events', + 'slots', + // 'transitions', // 'store' ]; @@ -114,6 +114,16 @@ class Parser extends EventEmitter { this.emit('data', item); } + emitMethodItem(method, isStaticScope, defaultVisibility) { + const item = Object.assign({}, utils.getComment(method.node, defaultVisibility), { + name: method.name, + args: method.args, + static: isStaticScope + }); + + this.emit('method', item); + } + emitComputedItem(computed, isStaticScope, defaultVisibility) { const item = Object.assign({}, utils.getComment(computed.node, defaultVisibility), { name: computed.name, @@ -158,6 +168,12 @@ class Parser extends EventEmitter { return; } + if (node.type === 'FunctionDeclaration') { + this.emitMethodItem(this.parseFunctionDeclaration(node), isStaticScope, 'private'); + + return; + } + if (node.type === 'ExportNamedDeclaration') { const declaration = node.declaration; if (declaration) { @@ -169,6 +185,11 @@ class Parser extends EventEmitter { return; } + + if (declaration.type === 'FunctionDeclaration') { + this.emitMethodItem(this.parseFunctionDeclaration(declaration), isStaticScope, 'public'); + return; + } } } @@ -207,13 +228,30 @@ class Parser extends EventEmitter { if (!this.imports.hasOwnProperty(importEntry.identifier)) { this.imports[importEntry.identifier] = importEntry; - if (importEntry.identifier && importEntry.identifier[0] === importEntry.identifier[0].toUpperCase()) { - this.emitImportedComponentItem(node, importEntry.identifier, importEntry.sourceFilename); - - return; + if (importEntry.identifier) { + if (importEntry.identifier[0] === importEntry.identifier[0].toUpperCase()) { + this.emitImportedComponentItem(node, importEntry.identifier, importEntry.sourceFilename); + return; + } else { + this.emitDataItem({ + node, + name: importEntry.identifier, + kind: 'const' + }, isStaticScope, 'private'); + } } } } + } else if (node.specifiers.length > 0) { + node.specifiers.forEach((specifier) => { + if (specifier.type === 'ImportSpecifier') { + this.emitDataItem({ + node: specifier, + name: specifier.local.name, + kind: 'const' + }, isStaticScope, 'private'); + } + }); } } @@ -253,6 +291,27 @@ class Parser extends EventEmitter { return result; } + parseFunctionDeclaration(node) { + if (node.type !== 'FunctionDeclaration') { + throw new Error('Node should have a FunctionDeclarationType, but is ' + node.type); + } + + const args = []; + node.params.forEach(param => { + if (param.type === 'Identifier') { + args.push({ + name: param.name, + }); + } + }); + + return { + node: node, + name: node.id.name, + args: args + }; + } + parseObjectProperty(node) { if (node.type !== 'Property') { throw new Error('Node should have a Property, but is ' + node.type); diff --git a/test/svelte3/integration/data/data.import.default.svelte b/test/svelte3/integration/data/data.import.default.svelte new file mode 100644 index 0000000..e59bfa2 --- /dev/null +++ b/test/svelte3/integration/data/data.import.default.svelte @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/test/svelte3/integration/data/data.import.many.svelte b/test/svelte3/integration/data/data.import.many.svelte new file mode 100644 index 0000000..9c1be6a --- /dev/null +++ b/test/svelte3/integration/data/data.import.many.svelte @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/test/svelte3/integration/data/data.spec.js b/test/svelte3/integration/data/data.spec.js index 86922d5..58d9f35 100644 --- a/test/svelte3/integration/data/data.spec.js +++ b/test/svelte3/integration/data/data.spec.js @@ -128,4 +128,60 @@ describe('SvelteDoc v3 - Props', () => { done(e); }); }); + + it('Imported default data should be parsed with comment', (done) => { + parser.parse({ + version: 3, + filename: path.resolve(__dirname, 'data.import.default.svelte'), + features: ['data'], + ignoredVisibilities: [] + }).then((doc) => { + expect(doc, 'Document should be provided').to.exist; + expect(doc.data, 'Document data should be parsed').to.exist; + + expect(doc.data.length).to.equal(1); + const prop = doc.data[0]; + expect(prop.name).to.equal('x'); + expect(prop.visibility).to.equal('private'); + expect(prop.static).to.be.false; + + expect(prop.description).to.equal('The import comment.'); + + expect(prop.type).to.equal('any'); + + done(); + }).catch(e => { + done(e); + }); + }); + + it('Imported many data should be parsed', (done) => { + parser.parse({ + version: 3, + filename: path.resolve(__dirname, 'data.import.many.svelte'), + features: ['data'], + ignoredVisibilities: [] + }).then((doc) => { + expect(doc, 'Document should be provided').to.exist; + expect(doc.data, 'Document data should be parsed').to.exist; + + expect(doc.data.length).to.equal(2); + + const prop1 = doc.data[0]; + expect(prop1.name).to.equal('y'); + expect(prop1.visibility).to.equal('private'); + expect(prop1.static).to.be.false; + expect(prop1.type).to.equal('any'); + + const prop2 = doc.data[1]; + expect(prop2.name).to.equal('z'); + expect(prop2.visibility).to.equal('private'); + expect(prop2.static).to.be.false; + expect(prop2.type).to.equal('any'); + + done(); + }).catch(e => { + done(e); + }); + }); }); \ No newline at end of file diff --git a/test/svelte3/integration/data/importable.js b/test/svelte3/integration/data/importable.js new file mode 100644 index 0000000..ccea985 --- /dev/null +++ b/test/svelte3/integration/data/importable.js @@ -0,0 +1,3 @@ +export default x = 1; +export let y = 1; +export let z = 1; \ No newline at end of file diff --git a/test/svelte3/integration/methods/method.private.svelte b/test/svelte3/integration/methods/method.private.svelte new file mode 100644 index 0000000..b2ab2f7 --- /dev/null +++ b/test/svelte3/integration/methods/method.private.svelte @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/test/svelte3/integration/methods/method.public.svelte b/test/svelte3/integration/methods/method.public.svelte new file mode 100644 index 0000000..fb5e714 --- /dev/null +++ b/test/svelte3/integration/methods/method.public.svelte @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/test/svelte3/integration/methods/methods.spec.js b/test/svelte3/integration/methods/methods.spec.js new file mode 100644 index 0000000..0c96e26 --- /dev/null +++ b/test/svelte3/integration/methods/methods.spec.js @@ -0,0 +1,62 @@ +const path = require('path'); +const chai = require('chai'); +const expect = chai.expect; + +const parser = require('../../../../index'); + +describe('SvelteDoc v3 - Methods', () => { + it('Private method should be parsed with comment and additional metadata', (done) => { + parser.parse({ + version: 3, + filename: path.resolve(__dirname, 'method.private.svelte'), + features: ['methods'], + ignoredVisibilities: [] + }).then((doc) => { + expect(doc, 'Document should be provided').to.exist; + expect(doc.methods, 'Document methods should be parsed').to.exist; + + expect(doc.methods.length).to.equal(1); + const method = doc.methods[0]; + expect(method.name).to.equal('privateMethod'); + expect(method.visibility).to.equal('private'); + expect(method.static).to.be.false; + + expect(method.args, 'Method arguments should be parsed').to.exist; + expect(method.args.length).to.equal(2); + expect(method.args[0].name).to.equal('param1'); + expect(method.args[1].name).to.equal('param2'); + + expect(method.description).to.equal('The method comment.'); + done(); + }).catch(e => { + done(e); + }); + }); + + it('Public method should be parsed with comment and additional metadata', (done) => { + parser.parse({ + version: 3, + filename: path.resolve(__dirname, 'method.public.svelte'), + features: ['methods'], + ignoredVisibilities: [] + }).then((doc) => { + expect(doc, 'Document should be provided').to.exist; + expect(doc.methods, 'Document methods should be parsed').to.exist; + + expect(doc.methods.length).to.equal(1); + const method = doc.methods[0]; + expect(method.name).to.equal('publicMethod'); + expect(method.visibility).to.equal('public'); + expect(method.static).to.be.false; + + expect(method.args, 'Method arguments should be parsed').to.exist; + expect(method.args.length).to.equal(2); + expect(method.args[0].name).to.equal('param1'); + expect(method.args[1].name).to.equal('param2'); + + done(); + }).catch(e => { + done(e); + }); + }); +}); \ No newline at end of file diff --git a/typings.d.ts b/typings.d.ts index 45f4703..753e0b8 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -138,6 +138,13 @@ export interface SvelteMethodArgumentItem { * The description of the parameter. */ description?: string; + /** + * Indicates that this data item of component located in static context. + * Variable should be declared in `