297 lines
6.4 KiB
JavaScript
297 lines
6.4 KiB
JavaScript
|
import traverse from '@babel/traverse';
|
||
|
import {expect} from 'chai';
|
||
|
|
||
|
import {parseCode} from '@flecks/dox/build/parser';
|
||
|
import {
|
||
|
buildFileVisitor,
|
||
|
configVisitor,
|
||
|
hookImplementationVisitor,
|
||
|
hookInvocationVisitor,
|
||
|
hookSpecificationVisitor,
|
||
|
hookVisitor,
|
||
|
todoVisitor,
|
||
|
} from '@flecks/dox/build/visitors';
|
||
|
|
||
|
async function confirmVisited(code, visitor, test) {
|
||
|
const visited = [];
|
||
|
traverse(
|
||
|
await parseCode(code),
|
||
|
visitor((result) => {
|
||
|
visited.push(result);
|
||
|
}),
|
||
|
);
|
||
|
test(visited);
|
||
|
}
|
||
|
|
||
|
function constHooksWrapper(code) {
|
||
|
return `
|
||
|
export const hooks = {
|
||
|
${code}
|
||
|
};
|
||
|
`;
|
||
|
}
|
||
|
|
||
|
function exportsHooksWrapper(code) {
|
||
|
return `
|
||
|
exports.hooks = {
|
||
|
${code}
|
||
|
};
|
||
|
`;
|
||
|
}
|
||
|
|
||
|
async function confirmVisitedWrapped(code, visitor, test) {
|
||
|
await Promise.all(
|
||
|
[constHooksWrapper, exportsHooksWrapper]
|
||
|
.map(async (wrapper) => {
|
||
|
const source = wrapper(code);
|
||
|
await confirmVisited(source, visitor, test(source));
|
||
|
}),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
it('parses hooks', async () => {
|
||
|
await confirmVisitedWrapped(
|
||
|
`
|
||
|
'hello': () => {},
|
||
|
`,
|
||
|
hookImplementationVisitor,
|
||
|
() => (visited) => {
|
||
|
expect(visited.length)
|
||
|
.to.equal(1);
|
||
|
expect(visited[0].key.value)
|
||
|
.to.equal('hello');
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('visits hooks', async () => {
|
||
|
await confirmVisitedWrapped(
|
||
|
`
|
||
|
'hello': () => {},
|
||
|
'goodbye': () => {},
|
||
|
`,
|
||
|
hookVisitor('hello'),
|
||
|
() => (visited) => {
|
||
|
expect(visited.length)
|
||
|
.to.equal(1);
|
||
|
expect(visited[0].key.value)
|
||
|
.to.equal('hello');
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
|
||
|
function buildFileWrappers(code) {
|
||
|
return [
|
||
|
`
|
||
|
'@flecks/build.files': () => ([
|
||
|
${code}
|
||
|
]),
|
||
|
`,
|
||
|
`
|
||
|
'@flecks/build.files': () => {
|
||
|
return [
|
||
|
${code}
|
||
|
];
|
||
|
},
|
||
|
`,
|
||
|
`
|
||
|
'@flecks/build.files': function f() {
|
||
|
return [
|
||
|
${code}
|
||
|
];
|
||
|
},
|
||
|
`,
|
||
|
];
|
||
|
}
|
||
|
|
||
|
it('visits build files', async () => {
|
||
|
await Promise.all(
|
||
|
buildFileWrappers(
|
||
|
`
|
||
|
/**
|
||
|
* This is a description.
|
||
|
*
|
||
|
* It is on multiple lines.
|
||
|
*/
|
||
|
'first.config.js',
|
||
|
/**
|
||
|
* This is another description.
|
||
|
*/
|
||
|
'second.config.js',
|
||
|
'third.config.js',
|
||
|
`,
|
||
|
)
|
||
|
.map(async (wrapped) => {
|
||
|
await confirmVisitedWrapped(
|
||
|
wrapped,
|
||
|
buildFileVisitor,
|
||
|
() => (visited) => {
|
||
|
expect(visited)
|
||
|
.to.deep.equal([
|
||
|
{
|
||
|
filename: 'first.config.js',
|
||
|
description: 'This is a description.\n\nIt is on multiple lines.',
|
||
|
},
|
||
|
{
|
||
|
filename: 'second.config.js',
|
||
|
description: 'This is another description.',
|
||
|
},
|
||
|
{
|
||
|
filename: 'third.config.js',
|
||
|
description: undefined,
|
||
|
},
|
||
|
]);
|
||
|
},
|
||
|
);
|
||
|
}),
|
||
|
);
|
||
|
});
|
||
|
|
||
|
function configWrappers(code) {
|
||
|
return [
|
||
|
`
|
||
|
'@flecks/core.config': () => ({
|
||
|
${code}
|
||
|
}),
|
||
|
`,
|
||
|
`
|
||
|
'@flecks/core.config': () => {
|
||
|
return {
|
||
|
${code}
|
||
|
};
|
||
|
},
|
||
|
`,
|
||
|
`
|
||
|
'@flecks/core.config': function f() {
|
||
|
return {
|
||
|
${code}
|
||
|
};
|
||
|
},
|
||
|
`,
|
||
|
];
|
||
|
}
|
||
|
|
||
|
it('visits config', async () => {
|
||
|
await Promise.all(
|
||
|
configWrappers(
|
||
|
`
|
||
|
/**
|
||
|
* Description.
|
||
|
*/
|
||
|
first: 'default',
|
||
|
second: 1111,
|
||
|
`,
|
||
|
)
|
||
|
.map(async (wrapped) => {
|
||
|
await confirmVisitedWrapped(
|
||
|
wrapped,
|
||
|
configVisitor,
|
||
|
(source) => (visited) => {
|
||
|
const expected = [
|
||
|
{
|
||
|
key: 'first',
|
||
|
description: 'Description.',
|
||
|
},
|
||
|
{
|
||
|
key: 'second',
|
||
|
description: undefined,
|
||
|
},
|
||
|
];
|
||
|
visited.forEach((config, i) => {
|
||
|
expect(config.key)
|
||
|
.to.equal(expected[i].key);
|
||
|
expect(config.description)
|
||
|
.to.equal(expected[i].description);
|
||
|
});
|
||
|
expect(source.slice(visited[0].location.start.index, visited[0].location.end.index))
|
||
|
.to.equal("'default'");
|
||
|
expect(source.slice(visited[1].location.start.index, visited[1].location.end.index))
|
||
|
.to.equal('1111');
|
||
|
},
|
||
|
);
|
||
|
}),
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('visits hook invocations', async () => {
|
||
|
await confirmVisited(
|
||
|
`
|
||
|
flecks.invoke('sup');
|
||
|
flecks.invokeAsync('yep');
|
||
|
flecks.gather('stuff');
|
||
|
flecks.nope();
|
||
|
this.invoke('sup');
|
||
|
this.invokeAsync('yep');
|
||
|
this.gather('stuff');
|
||
|
this.nope();
|
||
|
`,
|
||
|
hookInvocationVisitor,
|
||
|
(visited) => {
|
||
|
expect(visited.length)
|
||
|
.to.equal(8);
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('visits hook specifications', async () => {
|
||
|
const f = '(one, two) => { return one + parseInt(two, 10); }';
|
||
|
await confirmVisitedWrapped(
|
||
|
`
|
||
|
/**
|
||
|
* This is a hook.
|
||
|
* @param {number} one First.
|
||
|
* @param {string} two Second.
|
||
|
* @returns {number} Result.
|
||
|
*/
|
||
|
'hook': ${f},
|
||
|
`,
|
||
|
hookSpecificationVisitor,
|
||
|
(source) => (visited) => {
|
||
|
expect(visited.length)
|
||
|
.to.equal(1);
|
||
|
expect(visited[0].description)
|
||
|
.to.equal('This is a hook.');
|
||
|
expect(visited[0].hook)
|
||
|
.to.equal('hook');
|
||
|
expect(visited[0].returns)
|
||
|
.to.deep.equal({description: 'Result.', type: 'number'});
|
||
|
expect(visited[0].params)
|
||
|
.to.deep.equal([
|
||
|
{description: 'First.', name: 'one', type: 'number'},
|
||
|
{description: 'Second.', name: 'two', type: 'string'},
|
||
|
]);
|
||
|
expect(source.slice(visited[0].location.start.index, visited[0].location.end.index))
|
||
|
.to.equal(f);
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('visits todos', async () => {
|
||
|
const source = `
|
||
|
someStuff();
|
||
|
|
||
|
// @todo This should be a function.
|
||
|
new OhYeah();
|
||
|
|
||
|
// @todo This is a really
|
||
|
// long todo item.
|
||
|
something();
|
||
|
`;
|
||
|
await confirmVisited(
|
||
|
source,
|
||
|
todoVisitor,
|
||
|
(visited) => {
|
||
|
expect(visited.map(({description}) => description))
|
||
|
.to.deep.equal([
|
||
|
'This should be a function.',
|
||
|
'This is a really long todo item.',
|
||
|
]);
|
||
|
expect(visited.map(({location: {start, end}}) => (source.slice(start.index, end.index))))
|
||
|
.to.deep.equal([
|
||
|
'new OhYeah();',
|
||
|
'something();',
|
||
|
]);
|
||
|
},
|
||
|
);
|
||
|
});
|