Skip to content

Commit

Permalink
[Fixed] Solve issue #26, support export { variables as var } statem…
Browse files Browse the repository at this point in the history
…ent.

[Added] now interface `SvelteDataItem` provides a new property `localName` with information about internal name of component property.
  • Loading branch information
alexprey committed Aug 17, 2020
1 parent f86c48c commit d229c33
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

## UNRELEASED

## [3.0.1] 17.08.2020

- [Fixed] Solve issue #26, support `export { variables as var }` statement.
- [Added] now interface `SvelteDataItem` provides a new property `localName` with information about internal name of component property.

## [3.0.0] 08.08.2020

- [Fixed] Solve vulnerability issues:
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Generate a JSON documentation for a Svelte file

## Changelog

### [3.0.1] 17.08.2020

- [Fixed] Solve issue #26, support `export { variables as var }` statement.
- [Added] now interface `SvelteDataItem` provides a new property `localName` with information about internal name of component property.

### [3.0.0] 08.08.2020

- [Fixed] Solve vulnerability issues:
Expand Down
30 changes: 23 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,24 +74,32 @@ function convertVisibilityToLevel(visibility) {
return 0;
}

function mergeItems(itemType, currentItem, newItem) {
function mergeItems(itemType, currentItem, newItem, ignoreLocations) {
if (convertVisibilityToLevel(currentItem.visibility) < convertVisibilityToLevel(newItem.visibility)) {
currentItem.visibility = newItem.visibility;
}

if (!currentItem.description && newItem.description) {
currentItem.description = newItem;
currentItem.description = newItem.description;
}

if (!currentItem.type || currentItem.type.type === 'any') {
if (newItem.type && newItem.type.type !== 'any') {
currentItem.type = newItem.type;
}
}

if (!currentItem.keywords && newItem.keywords) {
currentItem.keywords = newItem.keywords;
}

if (newItem.locations && newItem.locations.length > 0) {
if (currentItem.locations) {
currentItem.locations.push(...newItem.locations);
} else {
currentItem.locations = [...newItem.locations];
if (!ignoreLocations) {
if (newItem.locations && newItem.locations.length > 0) {
if (currentItem.locations) {
currentItem.locations.push(...newItem.locations);
} else {
currentItem.locations = [...newItem.locations];
}
}
}

Expand Down Expand Up @@ -134,6 +142,14 @@ function subscribeOnParserEvents(parser, options, version, resolve, reject) {
parser.on(eventName, (value) => {
const itemIndex = component[feature].findIndex(item => item.name === value.name);

if (value.localName) {
const localItem = component[feature].find(item => item.name === value.localName);

if (localItem) {
value = mergeItems(feature, value, localItem, true);
}
}

if (itemIndex < 0) {
component[feature].push(value);
} else {
Expand Down
23 changes: 23 additions & 0 deletions lib/v3/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class Parser extends EventEmitter {
type: utils.inferTypeFromVariableDeclaration(variable),
importPath: variable.importPath,
originalName: variable.originalName,
localName: variable.localName
});

if (variable.declarator && variable.declarator.init) {
Expand Down Expand Up @@ -330,6 +331,7 @@ class Parser extends EventEmitter {

if (node.type === 'ExportNamedDeclaration' && level === 0 && parseContext.scopeType !== SCOPE_MARKUP) {
const declaration = node.declaration;
const specifiers = node.specifiers;

if (declaration) {
const exportNodeComment = utils.getCommentFromSourceCode(node, parseContext.sourceCode, { defaultVisibility: 'public', useLeading: true, useTrailing: false });
Expand All @@ -352,6 +354,27 @@ class Parser extends EventEmitter {
return;
}
}

if (specifiers) {
specifiers.forEach(specifier => {
if (specifier.type === 'ExportSpecifier') {
const exportedOrLocalName = specifier.exported
? specifier.exported.name
: specifier.local.name;

this.emitDataItem({
node: specifier,
name: exportedOrLocalName,
localName: specifier.local.name,
kind: 'const',
location: {
start: specifier.exported ? specifier.exported.start : specifier.local.start,
end: specifier.exported ? specifier.exported.end : specifier.local.end
}
}, parseContext, 'public');
}
});
}
}

if (node.type === 'LabeledStatement' && level === 0 && parseContext.scopeType !== SCOPE_MARKUP) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sveltedoc-parser",
"version": "3.0.0",
"version": "3.0.1",
"description": "Generate a JSON documentation for a Svelte file",
"main": "index.js",
"scripts": {
Expand Down
11 changes: 11 additions & 0 deletions test/svelte3/integration/data/data.export.aliace.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script>
/**
* Description for variable that must be exported later
* @type {Array<string>}
*/
const classes = [ 'btn' ];
export {
classes as class
};
</script>
7 changes: 7 additions & 0 deletions test/svelte3/integration/data/data.export.many.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
/* The `a` variable description */
let a = 1;
let b = 'Test';
export { a, b };
</script>
74 changes: 74 additions & 0 deletions test/svelte3/integration/data/data.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,78 @@ describe('SvelteDoc v3 - Props', () => {
done(e);
});
});

it('Export object statement with multiple variables should be parsed as public props', done => {
parser.parse({
version: 3,
filename: path.resolve(__dirname, 'data.export.many.svelte'),
features: ['data'],
includeSourceLocations: true,
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.find(d => d.name === 'a');

expect(prop1.name).to.equal('a');
expect(prop1.visibility).to.equal('public');
expect(prop1.static).to.be.false;
expect(prop1.description).to.be.equal('The `a` variable description');
expect(prop1.type).to.eql({ kind: 'type', type: 'number', text: 'number' });

expect(prop1.locations, 'Code location should be parsed').to.be.exist;
expect(prop1.locations[0]).is.deep.equals({ start: 58, end: 59 });
expect(prop1.locations[1]).is.deep.equals({ start: 102, end: 103 });

const prop2 = doc.data.find(d => d.name === 'b');

expect(prop2.name).to.equal('b');
expect(prop2.visibility).to.equal('public');
expect(prop2.static).to.be.false;
expect(prop2.type).to.eql({ kind: 'type', type: 'string', text: 'string' });

done();
}).catch(e => {
done(e);
});
});

it('Export object statement with variable and aliace for that should be parsed as public prop', done => {
parser.parse({
version: 3,
filename: path.resolve(__dirname, 'data.export.aliace.svelte'),
features: ['data'],
includeSourceLocations: true,
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 prop = doc.data.find(d => d.name === 'class');

expect(prop).to.exist;
expect(prop.name, 'Aliace name must be exposed instead of original name').to.equal('class');
expect(prop.localName, 'Local name must be stored').to.equal('classes');
expect(prop.visibility).to.equal('public');
expect(prop.static).to.be.false;
expect(prop.description).to.be.equal('Description for variable that must be exported later');
expect(prop.type).to.eql({ kind: 'type', type: 'Array<string>', text: 'Array<string>' });

expect(prop.locations, 'Code location should be parsed').to.be.exist;
expect(prop.locations[0]).is.deep.equals({ start: 189, end: 194 });

const localProp = doc.data.find(d => d.name === 'classes');

expect(localProp, 'Local prop definition also must be provided').to.exist;

done();
}).catch(e => {
done(e);
});
});
});
14 changes: 14 additions & 0 deletions typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ export interface SvelteDataItem extends ISvelteItem {
* @since {2.2.0}
*/
originalName?: string;

/**
* The local name of the prop that was exported with aliace statement
* @example
* ```js
* const local = 1;
* export { local as public };
* // `name` of this item will be `'public'`
* // `localName` of this item will be `'local'`
* ```
* @since {3.0.1}
*/
localName?: string;

/**
* The relative path of importing of this object.
* When not defined, so variable is not provided.
Expand Down

0 comments on commit d229c33

Please sign in to comment.