radashi-helper
Version:
Help with managing your own Radashi
188 lines (182 loc) • 5.9 kB
JavaScript
import {
dedent
} from "./chunk-V32CUL4H.js";
import {
isBabelNode,
loadRewired,
require_lib,
rewire
} from "./chunk-OCHPTCP5.js";
import {
findSources
} from "./chunk-652CQLOF.js";
import {
debug
} from "./chunk-DSXY7YVB.js";
import {
__toESM,
flat,
select,
traverse
} from "./chunk-VOEQFXI5.js";
// src/util/generateUmbrella.ts
import { existsSync } from "node:fs";
import { join as join2, relative } from "node:path";
// src/rewired/updateRewired.ts
import { copyFile } from "node:fs/promises";
import { join } from "node:path";
async function updateRewired(env) {
const prevRewired = await loadRewired(env);
if (prevRewired.length) {
debug(`Updating ${prevRewired.length} rewired files...`);
await Promise.all(
prevRewired.map(async (funcPath) => {
await rewire(funcPath, env);
})
);
await copyFile(
join(env.root, "overrides/src/tsconfig.json"),
join(env.root, "overrides/rewired/tsconfig.json")
);
}
}
// src/util/exports.ts
var import_parser = __toESM(require_lib(), 1);
import { readFileSync } from "node:fs";
function printExports(options) {
const names = options.names.concat(options.types.map((name) => `type ${name}`));
return `export { ${names.join(", ")} } from '${options.from}'`;
}
function extractExports(file, options = {}) {
const typesOption = options.types ?? true;
let fileContents;
try {
fileContents = readFileSync(file, "utf8");
} catch {
return [];
}
const parseResult = (0, import_parser.parse)(fileContents, {
plugins: [["typescript", { dts: file.endsWith(".d.ts") }]],
sourceType: "module",
sourceFilename: file
});
const names = /* @__PURE__ */ new Set();
const { program } = parseResult;
function isAllowed(node) {
return typesOption !== "only" && (node.type === "FunctionDeclaration" || node.type === "ClassDeclaration" || node.type === "ExportSpecifier" && node.exportKind !== "type") || typesOption !== false && (node.type === "TSInterfaceDeclaration" || node.type === "TSTypeAliasDeclaration" || node.type === "ExportSpecifier" && node.exportKind === "type");
}
traverse(program, (node, _key, _parent, context) => {
if (isBabelNode(node)) {
context.skip();
if (node.type === "ExportNamedDeclaration") {
if (node.declaration) {
if (node.declaration.type === "VariableDeclaration") {
if (typesOption === "only") {
return;
}
for (const declarator of node.declaration.declarations) {
if (declarator.id.type === "Identifier") {
names.add(declarator.id.name);
}
}
} else if (isAllowed(node.declaration)) {
if (node.declaration.id && node.declaration.id.type === "Identifier") {
names.add(node.declaration.id.name);
}
}
} else if (node.specifiers) {
for (const specifier of node.specifiers) {
if (specifier.type === "ExportSpecifier") {
if (isAllowed(specifier)) {
names.add(specifier.exported.name);
}
}
}
}
} else if (node.type === "ExportDefaultDeclaration") {
if (typesOption !== "only") {
names.add("default");
}
}
}
});
return Array.from(names).sort();
}
// src/util/generateUmbrella.ts
async function generateUmbrella(env) {
await updateRewired(env);
const typesPath = join2(env.root, "src/types.ts");
const overrideTypesPath = join2(env.root, "overrides/src/types.ts");
const pathsInside = await findSources(env);
const namesBlocked = flat(Object.values(pathsInside)).concat(typesPath, overrideTypesPath).flatMap((sourcePath) => {
return extractExports(sourcePath);
});
const filterBlockedNames = (exportName) => !namesBlocked.includes(exportName);
const upstreamPath = join2(env.root, "node_modules/radashi/dist/radashi.d.ts");
const upstreamTypes = extractExports(upstreamPath, { types: "only" }).filter(
filterBlockedNames
);
const upstreamExports = extractExports(upstreamPath).filter(filterBlockedNames);
let code = printExports({
from: "./node_modules/radashi/dist/radashi",
names: upstreamExports.filter((name) => !upstreamTypes.includes(name)),
types: upstreamTypes
});
const srcExports = printLocalExports(pathsInside.src, env);
if (srcExports.length) {
code += dedent`
\n
// Our custom functions.
${srcExports}
`;
}
const overrideExports = printLocalExports(pathsInside.overrides, env);
if (overrideExports.length) {
code += dedent`
\n
// Our overrides.
${overrideExports}
`;
}
const userTypeExports = existsSync(typesPath) ? printLocalExports([typesPath], env) : void 0;
const overrideTypeExports = existsSync(overrideTypesPath) ? printLocalExports([overrideTypesPath], env) : void 0;
if (userTypeExports?.length || overrideTypeExports?.length) {
code += dedent`
\n
// Our types.\n
`;
if (overrideTypeExports?.length) {
code += overrideTypeExports;
}
if (userTypeExports?.length) {
code += userTypeExports;
}
}
const rewiredExports = printLocalExports(pathsInside.rewired, env);
if (rewiredExports.length) {
code += dedent`
\n
// Rewired to use our overrides.
${rewiredExports}
`;
}
return code + "\n";
}
function printLocalExports(files, env) {
return select(
files.map((file) => ({
file,
exports: extractExports(file),
types: extractExports(file, { types: "only" })
})),
(mod) => printExports({
from: "./" + relative(env.root, mod.file),
names: mod.exports.filter((name) => !mod.types.includes(name)),
types: mod.types
}),
(mod) => mod.exports.length > 0
).join("\n");
}
export {
generateUmbrella
};