Skip to content

Commit

Permalink
Fix locations parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
alexprey committed Oct 2, 2019
1 parent 65bfbe9 commit bf2a926
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 18 deletions.
14 changes: 14 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}\\index.js"
}
]
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
## UNRELEASED

- [Added] Svelte V3: Implement support of script element locations
- [Fixed] Svelte V3: Fix parsing when component have multiple `<script>` blocks
- [Added] Spec: Property `locations` was added to items and presents the list of item code locations
- [Changed] Spec: Property `loc` for items marked as depricated, see `locations` property instead

Expand Down
38 changes: 20 additions & 18 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,27 @@ function loadFileStructureFromOptions(options) {
throw new Error('Can not load source from options, because nothing is not provided');
}

function extractHtmlBlock(content, blockName) {
let remainingContent = content;
function extractHtmlBlock(content, blockName, searchStartIndex) {
const blockOuterStartIndex = content.indexOf(`<${blockName}`, searchStartIndex);
if (blockOuterStartIndex >= 0) {
const blockInnerEndIndex = content.indexOf(`</${blockName}>`, blockOuterStartIndex + blockName.length + 1);

const blockStart = remainingContent.indexOf(`<${blockName}`);
if (blockStart >= 0) {
const blockEnd = remainingContent.indexOf(`</${blockName}>`, blockStart + blockName.length + 1);
if (blockInnerEndIndex >= 0) {
const openTagEndIndex = content.indexOf('>', blockOuterStartIndex + blockName.length);

if (blockEnd >= 0) {
const openTagEndIndex = remainingContent.indexOf('>', blockStart + blockName.length);

const attributes = remainingContent.substr(blockStart + blockName.length + 1, openTagEndIndex - blockStart - blockName.length - 1);
const innerBlockContent = remainingContent.substr(openTagEndIndex + 1, blockEnd - openTagEndIndex - 1);
const attributes = content.substr(blockOuterStartIndex + blockName.length + 1, openTagEndIndex - blockOuterStartIndex - blockName.length - 1);
const innerBlockContent = content.substr(openTagEndIndex + 1, blockInnerEndIndex - openTagEndIndex - 1);
const offset = openTagEndIndex + 1;

remainingContent = remainingContent.substr(0, blockStart) + remainingContent.substr(blockEnd + blockName.length + 3);
const blockOuterEndIndex = blockInnerEndIndex + blockName.length + 3;

return {
remainingContent: remainingContent,
block: {
offset: offset,
outerPosition: {
start: blockOuterStartIndex,
end: blockOuterEndIndex
},
content: innerBlockContent,
attributes: attributes
}
Expand All @@ -58,32 +59,33 @@ function extractHtmlBlock(content, blockName) {
}

return {
remainingContent: content,
block: null
}
};
}

function extractAllHtmlBlocks(content, blockName) {
const blocks = [];

let searchResult = extractHtmlBlock(content, blockName);
if (searchResult.block) {
while (searchResult.block) {
blocks.push(searchResult.block);

const searchStartIndex = searchResult.block.outerPosition.end;
searchResult = extractHtmlBlock(content, blockName, searchStartIndex);
}

return {
remainingContent: searchResult.remainingContent,
blocks: blocks
};
}

function parseFileStructureFromContent(fileContent) {
const scriptBlocksSearchResult = extractAllHtmlBlocks(fileContent, 'script');
const styleBlocksSearchResult = extractAllHtmlBlocks(scriptBlocksSearchResult.remainingContent, 'style');
const styleBlocksSearchResult = extractAllHtmlBlocks(fileContent, 'style');

return {
content: fileContent,
template: styleBlocksSearchResult.remainingContent,
template: fileContent,
scripts: scriptBlocksSearchResult.blocks,
styles: styleBlocksSearchResult.blocks
}
Expand Down
10 changes: 10 additions & 0 deletions test/svelte3/integration/locations/locations.multiscripts.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<h1>Template header</h1>
<p>Template text</p>

<script scope="module">
let staticVariable = 1;
</script>

<script>
let variable = 1;
</script>
41 changes: 41 additions & 0 deletions test/svelte3/integration/locations/locations.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const path = require('path');
const chai = require('chai');
const expect = chai.expect;

const parser = require('../../../../index');

function assertDataItemLocation(dataItem, expectedLocationStart, expectedLocationEnd) {
expect(dataItem.locations, `Code location for data item should be included for "${dataItem.name}"`).to.be.exist;
expect(dataItem.locations.length, `Code location for data item have values for "${dataItem.name}"`).to.be.equal(1);
const location = dataItem.locations[0];
expect(location, `Location should be correct identified for "${dataItem.name}"`).is.deep.equals({ start: expectedLocationStart, end: expectedLocationEnd });
}

describe('SvelteDoc v3 - Locations', () => {
it('Locations for multiple scripts should be found correct', (done) => {
parser.parse({
version: 3,
filename: path.resolve(__dirname, 'locations.multiscripts.svelte'),
features: ['data'],
includeSourceLocations: true,
ignoredVisibilities: []
}).then((doc) => {
expect(doc, 'Document should be provided').to.exist;
expect(doc.data, 'Document events should be parsed').to.exist;

const static = doc.data.find(p => p.name === 'staticVariable');
expect(static, '"staticVariable" should be presented in data items of the doc').to.exist;
expect(static.static).to.be.true;
assertDataItemLocation(static, 83, 97);

const local = doc.data.find(p => p.name === 'variable');
expect(local, '"variable" should be presented in data items of the doc').to.exist;
expect(local.static).to.be.false;
assertDataItemLocation(local, 135, 143);

done();
}).catch(e => {
done(e);
});
});
});
120 changes: 120 additions & 0 deletions test/unit/helpers/helpers.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
const chai = require('chai');
const expect = chai.expect;

const helpers = require("../../../lib/helpers");

describe('Helpers parser module tests', () => {
describe('helpers.extractHtmlBlock', () => {
it('When html block exists should be provide a correct result', () => {
const content = `
<p>Some content here</p>
<script>
let variable = 1;
</script>
`;

const result = helpers.extractHtmlBlock(content, 'script');

expect(result).is.exist;
const block = result.block;
expect(block).is.exist;
expect(block.content).is.eq('\nlet variable = 1;\n');
expect(block.offset).is.eq(34);
expect(block.outerPosition).is.exist;
expect(block.outerPosition.start).is.eq(26);
expect(block.outerPosition.end).is.eq(62);
expect(block.attributes).is.empty;
});

it('When html block have attribute, should be correct extracted', () => {
const content = `
<p>Some content here</p>
<script scope="module">
let variable = 1;
</script>
`;

const result = helpers.extractHtmlBlock(content, 'script');

expect(result).is.exist;
const block = result.block;
expect(block).is.exist;
expect(block.attributes).is.eq(' scope="module"');
});

it('When startIndex are specified, should be skip first content and provide the next item', () => {
const content = `
<p>Some content here</p>
<script>
let variable = 1;
</script>
<script>
let variable = 2;
</script>
`;

const result = helpers.extractHtmlBlock(content, 'script', 62);

expect(result).is.exist;
const block = result.block;
expect(block).is.exist;
expect(block.content).is.eq('\nlet variable = 2;\n');
expect(block.offset).is.eq(71);
expect(block.outerPosition).is.exist;
expect(block.outerPosition.start).is.eq(63);
expect(block.outerPosition.end).is.eq(99);
expect(block.attributes).is.empty;
});
});

describe('helpers.extractAllHtmlBlocks', () => {
it('Extract one script block', () => {
const content = `
<p>Some content here</p>
<script>
let variable = 1;
</script>
`;
const result = helpers.extractAllHtmlBlocks(content, 'script');

expect(result).is.exist;
expect(result.blocks).is.exist;
expect(result.blocks.length).is.eq(1);

const block = result.blocks[0];
expect(block).is.exist;
expect(block.offset).is.eq(34);
expect(block.content).is.eq('\nlet variable = 1;\n');
expect(block.attributes).is.empty;
});

it('Extract two script blocks', () => {
const content = `
<p>Some content here</p>
<script>
let variable = 1;
</script>
<script>
let variable = 2;
</script>
`;
const result = helpers.extractAllHtmlBlocks(content, 'script');

expect(result).is.exist;
expect(result.blocks).is.exist;
expect(result.blocks.length).is.eq(2);

let block = result.blocks[0];
expect(block).is.exist;
expect(block.offset).is.eq(34);
expect(block.content).is.eq('\nlet variable = 1;\n');
expect(block.attributes).is.empty;

block = result.blocks[1];
expect(block).is.exist;
expect(block.offset).is.eq(71);
expect(block.content).is.eq('\nlet variable = 2;\n');
expect(block.attributes).is.empty;
});
});
});

0 comments on commit bf2a926

Please sign in to comment.