diff --git a/index.js b/index.js
index fc51618..af30601 100644
--- a/index.js
+++ b/index.js
@@ -61,6 +61,39 @@ function getEventName(feature) {
: feature;
}
+function convertVisibilityToLevel(visibility) {
+ switch (visibility) {
+ case 'public':
+ return 3;
+ case 'protected':
+ return 2;
+ case 'private':
+ return 1;
+ }
+
+ return 0;
+}
+
+function mergeItems(currentItem, newItem) {
+ if (convertVisibilityToLevel(currentItem.visibility) < convertVisibilityToLevel(newItem.visibility)) {
+ currentItem.visibility = newItem.visibility;
+ }
+
+ if (!currentItem.description && newItem.description) {
+ currentItem.description = newItem;
+ }
+
+ if (!currentItem.keywords && newItem.keywords) {
+ currentItem.keywords = newItem.keywords;
+ }
+
+ if (!currentItem.bind && newItem.bind) {
+ currentItem.bind = newItem.bind;
+ }
+
+ return currentItem;
+}
+
function subscribeOnParserEvents(parser, options, version, resolve, reject) {
const component = {
version: version
@@ -90,7 +123,13 @@ function subscribeOnParserEvents(parser, options, version, resolve, reject) {
if (itemIndex < 0) {
component[feature].push(value);
} else {
- component[feature][itemIndex] = value;
+ // Use merge logic of items information for specific features
+ if (['data'].includes(feature)) {
+ const currentItem = component[feature][itemIndex];
+ component[feature][itemIndex] = mergeItems(currentItem, value);
+ } else {
+ component[feature][itemIndex] = value;
+ }
}
});
}
diff --git a/lib/utils.js b/lib/utils.js
index ac9c061..8c99122 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -70,12 +70,14 @@ const parseComment = (text, defaultVisibility = DEFAULT_VISIBILITY, features = [
const getComment = (property, defaultVisibility = DEFAULT_VISIBILITY, features, useLeading = true, useTrailing = true) => {
let lastComment = null;
- if (useLeading && property.leadingComments && property.leadingComments.length > 0) {
- lastComment = property.leadingComments[property.leadingComments.length - 1].value;
- }
-
- if (useTrailing && property.trailingComments && property.trailingComments.length > 0) {
- lastComment = property.trailingComments[property.trailingComments.length - 1].value;
+ if (property) {
+ if (useLeading && property.leadingComments && property.leadingComments.length > 0) {
+ lastComment = property.leadingComments[property.leadingComments.length - 1].value;
+ }
+
+ if (useTrailing && property.trailingComments && property.trailingComments.length > 0) {
+ lastComment = property.trailingComments[property.trailingComments.length - 1].value;
+ }
}
if (lastComment) {
diff --git a/lib/v3/parser.js b/lib/v3/parser.js
index 7b9e39f..0e9af47 100644
--- a/lib/v3/parser.js
+++ b/lib/v3/parser.js
@@ -569,6 +569,46 @@ class Parser extends EventEmitter {
lastComment = null;
}
+ if (this.features.includes('data')) {
+ const bindProperties = Object.keys(attrs)
+ .filter(name => name.length > 5 && name.indexOf('bind:') === 0)
+ .filter(name => name !== 'bind:this')
+ .map(name => {
+ const sourcePropertyName = name.substr(5);
+ let targetPropertyName = sourcePropertyName;
+ const attributeValue = attrs[name];
+ if (attributeValue && attributeValue.length > 2 && attributeValue.charAt(0) === '{' && attributeValue.charAt(attributeValue.length - 1) === '}') {
+ targetPropertyName = attributeValue.substr(1, attributeValue.length - 2);
+ }
+
+ return {
+ sourcePropertyName: sourcePropertyName,
+ targetPropertyName: targetPropertyName,
+ parent: tagName,
+ loc: this.includeSourceLocations && lastAttributeLocations.hasOwnProperty(name)
+ ? lastAttributeLocations[name]
+ : null
+ };
+ });
+
+ bindProperties.forEach(bindProperty => {
+ const dataItem = {
+ name: bindProperty.targetPropertyName,
+ kind: 'let',
+ bind: {
+ source: bindProperty.parent,
+ property: bindProperty.sourcePropertyName
+ },
+ loc: bindProperty.loc,
+ visibility: 'private',
+ static: false,
+ readonly: false
+ };
+
+ this.emit('data', dataItem);
+ });
+ }
+
if (this.features.includes('refs')) {
if (attrs.hasOwnProperty('bind:this') && attrs['bind:this']) {
const value = attrs['bind:this'];
diff --git a/test/svelte3/integration/bind/bind.exported.svelte b/test/svelte3/integration/bind/bind.exported.svelte
new file mode 100644
index 0000000..e39cbdb
--- /dev/null
+++ b/test/svelte3/integration/bind/bind.exported.svelte
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/test/svelte3/integration/bind/bind.spec.js b/test/svelte3/integration/bind/bind.spec.js
index 146ab0c..7c34b79 100644
--- a/test/svelte3/integration/bind/bind.spec.js
+++ b/test/svelte3/integration/bind/bind.spec.js
@@ -82,4 +82,31 @@ describe('SvelteDoc v3 - Bind', () => {
done(e);
});
});
+
+ it('Bind declared and exported definition should be parsed', (done) => {
+ parser.parse({
+ version: 3,
+ filename: path.resolve(__dirname, 'bind.exported.svelte'),
+ features: ['data', 'description'],
+ 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 item = doc.data[0];
+
+ expect(item, 'Bind item should be a valid entity').to.exist;
+ expect(item.name).to.equal('totalCost');
+ expect(item.visibility).to.equal('public');
+ expect(item.description).to.equal('The comment of public binded property.');
+ expect(item.bind, 'Bind information should be presented').to.exist;
+ expect(item.bind.source).to.equal('ShopingCart');
+ expect(item.bind.property).to.equal('totalCost');
+
+ done();
+ }).catch(e => {
+ done(e);
+ });
+ });
});
\ No newline at end of file
diff --git a/typings.d.ts b/typings.d.ts
index eaadfda..c2cdc30 100644
--- a/typings.d.ts
+++ b/typings.d.ts
@@ -98,7 +98,7 @@ export interface SvelteDataItem extends ISvelteItem {
* @since Svelte V3
* @since {2.0.0}
*/
- let?: 'var'|'let'|'const';
+ kind?: 'var'|'let'|'const';
/**
* Provides information about property binding.
* @since Svelte V3