Skip to content

Commit

Permalink
Implement property bind parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
alexprey committed Aug 9, 2019
1 parent 89c7147 commit cd50a23
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 8 deletions.
41 changes: 40 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
}
});
}
Expand Down
14 changes: 8 additions & 6 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
40 changes: 40 additions & 0 deletions lib/v3/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand Down
10 changes: 10 additions & 0 deletions test/svelte3/integration/bind/bind.exported.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<ShopingCart bind:totalCost={totalCost} />

<script>
import ShopingCart from './ShopingCart.svelte';
/**
* The comment of public binded property.
*/
export let totalCost;
</script>
27 changes: 27 additions & 0 deletions test/svelte3/integration/bind/bind.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
2 changes: 1 addition & 1 deletion typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit cd50a23

Please sign in to comment.