flecks/packages/core/build/explicate.js
2024-01-20 03:58:07 -06:00

142 lines
4.1 KiB
JavaScript

const {
join,
resolve,
} = require('path');
module.exports = async function explicate(
maybeAliasedPaths,
{
importer,
platforms = ['server'],
resolver,
root,
},
) {
const descriptors = {};
const seen = {};
const roots = {};
function createDescriptor(maybeAliasedPath) {
const index = maybeAliasedPath.indexOf(':');
return -1 === index
? {
path: maybeAliasedPath,
request: maybeAliasedPath,
}
: {
path: maybeAliasedPath.slice(0, index),
request: resolve(root, maybeAliasedPath.slice(index + 1)),
};
}
async function doExplication(descriptor) {
const {path, request} = descriptor;
if (
platforms
.filter((platform) => platform.startsWith('!'))
.map((platform) => platform.slice(1))
.includes(path.split('/').pop())
) {
return;
}
if (path !== request) {
resolver.addAlias(path, request);
}
descriptors[request] = descriptor;
}
async function getRootDescriptor(descriptor) {
const {path, request} = descriptor;
// Walk up and find the root, if any.
const pathParts = path.split('/');
const requestParts = request.split('/');
let rootDescriptor;
while (pathParts.length > 0 && requestParts.length > 0) {
const candidate = requestParts.join('/');
// eslint-disable-next-line no-await-in-loop
if (await resolver.resolve(join(candidate, 'package.json'))) {
rootDescriptor = {
path: pathParts.join('/'),
request: requestParts.join('/'),
};
break;
}
pathParts.pop();
requestParts.pop();
}
return rootDescriptor;
}
function descriptorsAreTheSame(l, r) {
return (l && !r) || (!l && r) ? false : l.request === r.request;
}
async function explicateDescriptor(descriptor) {
if (descriptors[descriptor.request] || seen[descriptor.request]) {
return;
}
seen[descriptor.request] = true;
const areDescriptorsTheSame = descriptorsAreTheSame(
descriptor,
await getRootDescriptor(descriptor),
);
const resolved = await resolver.resolve(descriptor.request);
if (resolved || areDescriptorsTheSame) {
// eslint-disable-next-line no-use-before-define
await explicateRoot(descriptor);
}
if (!resolved && areDescriptorsTheSame) {
descriptors[descriptor.request] = descriptor;
}
if (resolved) {
await doExplication(descriptor);
}
await Promise.all(
platforms
.filter((platform) => !platform.startsWith('!'))
.map(async (platform) => {
if (await resolver.resolve(join(descriptor.request, platform))) {
return doExplication({
path: join(descriptor.path, platform),
request: join(descriptor.request, platform),
});
}
if (await resolver.resolve(join(descriptor.request, 'src', platform))) {
return doExplication({
path: join(descriptor.path, platform),
request: join(descriptor.request, 'src', platform),
});
}
return undefined;
}),
);
}
async function explicateRoot(descriptor) {
// Walk up and find the root, if any.
const rootDescriptor = await getRootDescriptor(descriptor);
if (!rootDescriptor || roots[rootDescriptor.request]) {
return;
}
const {request} = rootDescriptor;
roots[request] = true;
// Import bootstrap script.
const bootstrapPath = await resolver.resolve(join(request, 'build', 'flecks.bootstrap'));
const bootstrap = bootstrapPath ? importer(bootstrapPath) : {};
roots[request] = bootstrap;
// Explicate dependcies.
const {dependencies = []} = bootstrap;
if (dependencies.length > 0) {
await Promise.all(
dependencies
.map(createDescriptor)
.map(explicateDescriptor),
);
}
await explicateDescriptor(rootDescriptor);
}
await Promise.all(
maybeAliasedPaths
.map(createDescriptor)
.map(explicateDescriptor),
);
return {
descriptors,
roots,
};
};