2024-01-16 00:28:20 -06:00
|
|
|
const {readFile} = require('fs/promises');
|
2024-01-23 09:06:00 -06:00
|
|
|
const {join, relative} = require('path');
|
2022-03-07 00:21:16 -06:00
|
|
|
|
2024-01-16 00:28:20 -06:00
|
|
|
const {transformAsync} = require('@babel/core');
|
2024-01-20 04:31:37 -06:00
|
|
|
const {default: traverse} = require('@babel/traverse');
|
2024-01-16 00:28:20 -06:00
|
|
|
const {glob} = require('@flecks/core/server');
|
2022-03-07 00:21:16 -06:00
|
|
|
|
2024-01-23 09:06:00 -06:00
|
|
|
const {
|
|
|
|
buildFileVisitor,
|
|
|
|
configVisitor,
|
|
|
|
hookImplementationVisitor,
|
|
|
|
hookInvocationVisitor,
|
|
|
|
hookSpecificationVisitor,
|
|
|
|
todoVisitor,
|
|
|
|
} = require('./visitors');
|
2022-03-07 00:21:16 -06:00
|
|
|
|
2024-01-23 09:06:00 -06:00
|
|
|
exports.parseCode = async (code) => {
|
|
|
|
const {ast} = await transformAsync(code, {ast: true, code: false});
|
|
|
|
return ast;
|
|
|
|
};
|
2022-03-09 08:51:10 -06:00
|
|
|
|
2024-01-23 09:06:00 -06:00
|
|
|
exports.parseNormalSource = async (path, source) => {
|
|
|
|
const ast = await exports.parseCode(source);
|
|
|
|
const buildFiles = [];
|
|
|
|
const configs = [];
|
|
|
|
const hookImplementations = [];
|
|
|
|
const hookInvocations = [];
|
|
|
|
const todos = [];
|
|
|
|
const pushOne = (array) => (element) => {
|
|
|
|
array.push(element);
|
|
|
|
};
|
|
|
|
traverse(ast, buildFileVisitor(pushOne(buildFiles)));
|
|
|
|
traverse(ast, configVisitor((config) => {
|
|
|
|
const {description, key, location: {start: {index: start}, end: {index: end}}} = config;
|
|
|
|
configs.push({
|
|
|
|
defaultValue: source.slice(start, end),
|
|
|
|
description,
|
|
|
|
key,
|
2022-03-09 14:43:54 -06:00
|
|
|
});
|
2024-01-23 09:06:00 -06:00
|
|
|
}));
|
|
|
|
traverse(ast, hookImplementationVisitor((hookImplementation) => {
|
|
|
|
const {key: {value: hook}, loc: {start: {column, line}}} = hookImplementation;
|
|
|
|
hookImplementations.push({
|
|
|
|
column,
|
|
|
|
hook,
|
|
|
|
line,
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
traverse(ast, hookInvocationVisitor((hookInvocation) => {
|
|
|
|
const isClassFile = [
|
|
|
|
'@flecks/core/build/flecks.js',
|
|
|
|
'@flecks/build/build/build.js',
|
|
|
|
]
|
|
|
|
.includes(path);
|
|
|
|
if (!isClassFile && hookInvocation.isThis) {
|
|
|
|
return;
|
2022-03-07 00:21:16 -06:00
|
|
|
}
|
2024-01-23 09:06:00 -06:00
|
|
|
const {location: {start: {column, line}}, hook, type} = hookInvocation;
|
|
|
|
hookInvocations.push({
|
|
|
|
column,
|
|
|
|
hook,
|
|
|
|
line,
|
|
|
|
type,
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
traverse(ast, todoVisitor((todo) => {
|
|
|
|
const {description, location: {start: {index: start}, end: {index: end}}} = todo;
|
|
|
|
todos.push({
|
|
|
|
context: source.slice(start, end),
|
|
|
|
description,
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
return {
|
|
|
|
buildFiles,
|
|
|
|
config: configs,
|
|
|
|
hookImplementations,
|
|
|
|
hookInvocations,
|
|
|
|
todos,
|
2022-03-07 00:21:16 -06:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-01-23 09:06:00 -06:00
|
|
|
exports.parseHookSpecificationSource = async (path, source) => {
|
2024-01-16 00:28:20 -06:00
|
|
|
const ast = await exports.parseCode(source);
|
2024-01-23 09:06:00 -06:00
|
|
|
const hookSpecifications = [];
|
|
|
|
traverse(ast, hookSpecificationVisitor((hookSpecification) => {
|
|
|
|
const {
|
|
|
|
description,
|
|
|
|
hook,
|
|
|
|
location: {start: {index: start}, end: {index: end}},
|
|
|
|
params,
|
|
|
|
} = hookSpecification;
|
|
|
|
hookSpecifications.push({
|
|
|
|
description,
|
|
|
|
example: source.slice(start, end),
|
|
|
|
hook,
|
|
|
|
params,
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
return {
|
|
|
|
hookSpecifications,
|
|
|
|
};
|
2022-03-07 00:21:16 -06:00
|
|
|
};
|
|
|
|
|
2024-01-23 09:06:00 -06:00
|
|
|
exports.parseSource = async (path, source) => {
|
|
|
|
if (path.match(/build\/flecks\.hooks\.js$/)) {
|
|
|
|
return exports.parseHookSpecificationSource(path, source);
|
2022-03-07 00:21:16 -06:00
|
|
|
}
|
2024-01-23 09:06:00 -06:00
|
|
|
return exports.parseNormalSource(path, source);
|
2022-03-07 00:21:16 -06:00
|
|
|
};
|
|
|
|
|
2024-01-23 09:06:00 -06:00
|
|
|
exports.parseFleckRoot = async (path, root) => (
|
|
|
|
Promise.all(
|
|
|
|
(await Promise.all([
|
|
|
|
...await glob(join(root, 'src', '**', '*.js')),
|
|
|
|
...await glob(join(root, 'build', '**', '*.js')),
|
|
|
|
]))
|
|
|
|
.map((filename) => [relative(root, filename), filename])
|
|
|
|
.map(async ([path, filename]) => {
|
|
|
|
const buffer = await readFile(filename);
|
|
|
|
return [path, await exports.parseSource(path, buffer.toString('utf8'))];
|
2022-03-07 00:21:16 -06:00
|
|
|
}),
|
2024-01-23 09:06:00 -06:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
exports.parseFlecks = async (flecks) => (
|
|
|
|
Promise.all(
|
|
|
|
Object.entries(flecks.roots)
|
|
|
|
.map(async ([path, {root}]) => [path, await exports.parseFleckRoot(path, root)]),
|
|
|
|
)
|
|
|
|
);
|